diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..77a9fe47 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 870a0b4b01ac315df1b54f25c531f0cd +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 4c53e1ac..00000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,41 +0,0 @@ -[bumpversion] -current_version = 0.9.0 -commit = True -tag = True -parse = (?P\d+)(\.(?P\d+))?(\.(?P\d+))?((?P(a|b|rc))(?P
\d+))?(\.post(?P\d+))?(\.dev(?P\d+))?(\+(?P.+))?
-serialize = 
-	{major}.{minor}.{patch}{cycle}{pre}.post{post}.dev{dev}+{local}
-	{major}.{minor}.{patch}{cycle}{pre}.post{post}.dev{dev}
-	{major}.{minor}.{patch}{cycle}{pre}.post{post}+{local}
-	{major}.{minor}.{patch}{cycle}{pre}.post{post}
-	{major}.{minor}.{patch}{cycle}{pre}.dev{dev}+{local}
-	{major}.{minor}.{patch}{cycle}{pre}.dev{dev}
-	{major}.{minor}.{patch}{cycle}{pre}+{local}
-	{major}.{minor}.{patch}{cycle}{pre}
-	{major}.{minor}.{patch}.post{post}.dev{dev}+{local}
-	{major}.{minor}.{patch}.post{post}.dev{dev}
-	{major}.{minor}.{patch}.post{post}+{local}
-	{major}.{minor}.{patch}.post{post}
-	{major}.{minor}.{patch}.dev{dev}+{local}
-	{major}.{minor}.{patch}.dev{dev}
-	{major}.{minor}.{patch}+{local}
-	{major}.{minor}.{patch}
-
-[bumpversion:part:cycle]
-values = 
-	final
-	a
-	b
-	rc
-
-[bumpversion:file:pyproject.toml]
-search = version = "{current_version}"
-replace = version = "{new_version}"
-
-[bumpversion:file:koapy/__init__.py]
-search = __version__ = "{current_version}"
-replace = __version__ = "{new_version}"
-
-[bumpversion:file:setup.py]
-search = version="{current_version}"
-replace = version="{new_version}"
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 8310f585..00000000
--- a/.coveragerc
+++ /dev/null
@@ -1,2 +0,0 @@
-[run]
-source = koapy
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 167d2e25..00000000
--- a/.editorconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-# http://editorconfig.org
-
-root = true
-
-[*]
-indent_style = space
-indent_size = 4
-charset = utf-8
-end_of_line = lf
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[Makefile]
-indent_style = tab
-
-[LICENSE]
-insert_final_newline = false
-
-[*.bat]
-indent_style = tab
-end_of_line = crlf
diff --git a/.flake8 b/.flake8
deleted file mode 100644
index 64444b63..00000000
--- a/.flake8
+++ /dev/null
@@ -1,7 +0,0 @@
-[flake8]
-extend-exclude = docs,*_pb2.py,*_pb2_grpc.py
-max-line-length = 88
-extend-ignore = E203
-count = true
-statistics = true
-show-source = true
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index fe2bd4d3..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-docs/**/*.ipynb linguist-documentation
\ No newline at end of file
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 1f651cfb..00000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-# These are supported funding model platforms
-
-github: elbakramer
-custom: ["https://toon.at/donate/637521884081401532"]
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 8b137891..00000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index ecd36cf6..00000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-If applicable, add commands, codes, logs to help explain what you've done.
-```
-Paste the command(s) you ran and the output.
-If there was a crash, please include the traceback here.
-```
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Environment (please complete the following information):**
- - OS: [e.g. Windows 10]
- - Python Version: [e.g. Python 3.8 64Bit]
- - KOAPY Version: [e.g. 0.1.12]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 11fc491e..00000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/actions/check-version/.dockerignore b/.github/actions/check-version/.dockerignore
deleted file mode 100644
index e947317d..00000000
--- a/.github/actions/check-version/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-/action.yml
diff --git a/.github/actions/check-version/Dockerfile b/.github/actions/check-version/Dockerfile
deleted file mode 100644
index d993f1e7..00000000
--- a/.github/actions/check-version/Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM python:3.8-slim
-
-RUN apt-get update && apt-get install -y git && apt-get clean
-RUN pip install click packaging dunamai actions-toolkit
-COPY docker-entrypoint.py /usr/local/bin/docker-entrypoint.py
-
-ENTRYPOINT ["python", "/usr/local/bin/docker-entrypoint.py"]
diff --git a/.github/actions/check-version/action.yml b/.github/actions/check-version/action.yml
deleted file mode 100644
index e9fc4b53..00000000
--- a/.github/actions/check-version/action.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-name: Check version
-description: Chceck version status
-inputs:
-  vcs:
-    description: vcs
-    required: true
-    default: any
-  metadata:
-    description: metadata
-    required: false
-  no_metadata:
-    description: no metadata
-    required: false
-  dirty:
-    description: dirty
-    required: false
-  tagged_metadata:
-    description: tagged metadata
-    required: false
-  pattern:
-    description: pattern
-    required: false
-  format:
-    description: format
-    required: false
-  style:
-    description: style
-    required: false
-  latest_tag:
-    description: latest tag
-    required: false
-  bump:
-    description: bump
-    required: false
-  tag_dir:
-    description: tag dir
-    required: false
-  is_postrelease:
-    description: is postrelease
-    required: false
-outputs:
-  version:
-    description: version
-  is_finalrelease:
-    description: is final release
-  public:
-    description: public
-  base_version:
-    description: base version
-  epoch:
-    description: epoch
-  release:
-    description: release
-  major:
-    description: major
-  minor:
-    description: minor
-  micro:
-    description: micro
-  local:
-    description: local
-  pre:
-    description: pre
-  is_prerelease:
-    description: is_prerelease
-  dev:
-    description: dev
-  is_devrelease:
-    description: is_devrelease
-  post:
-    description: post
-  is_postrelease:
-    description: is_postrelease
-runs:
-  using: docker
-  image: Dockerfile
diff --git a/.github/actions/check-version/docker-entrypoint.py b/.github/actions/check-version/docker-entrypoint.py
deleted file mode 100644
index 794526a0..00000000
--- a/.github/actions/check-version/docker-entrypoint.py
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/env python
-
-import json
-
-import click
-
-from actions_toolkit import core
-
-
-class BooleanOption(click.Option):
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.type = click.Choice(["true", "false", ""], case_sensitive=False)
-        self.callback = self._callback
-        self._option_parser = None
-        self._option_parser__match_long_opt = None
-        self._option = None
-        self._option_process = None
-
-    def _callback(self, ctx, param, value):
-        if value and isinstance(value, str):
-            value = json.loads(value.lower())
-        return value
-
-    def _get_value_from_state(self, opt, option, state):
-        if state.rargs and not any(
-            state.rargs[0].startswith(prefix) for prefix in self._option.prefixes
-        ):
-            return state.rargs.pop(0)
-
-    def _match_long_opt(self, opt, explicit_value, state):
-        try:
-            self._option_parser__match_long_opt(opt, explicit_value, state)
-        except click.BadOptionUsage:
-            option = self._option_parser._long_opt.get(opt)
-            if not option:
-                return
-            if explicit_value is not None:
-                value = explicit_value
-            else:
-                value = self._get_value_from_state(opt, option, state)
-            option.process(value, state)
-
-    def _process(self, value, state):
-        if value is None:
-            value = True
-        elif not value:
-            value = None
-        state.opts[self._option.dest] = value
-        state.order.append(self._option.obj)
-
-    def add_to_parser(self, parser, ctx):
-        self._option_parser = parser
-        self._option_parser__match_long_opt = parser._match_long_opt
-        parser._match_long_opt = self._match_long_opt
-        super().add_to_parser(parser, ctx)
-        for name in self.opts:
-            option = parser._long_opt.get(name) or parser._short_opt.get(name)
-            if option:
-                self._option = option
-                self._option_process = option.process
-                option.process = self._process
-                break
-
-
-@click.command()
-@click.argument("vcs", default=core.get_input("vcs", required=False) or "any")
-@click.option(
-    "--metadata", cls=BooleanOption, default=core.get_input("metadata", required=False)
-)
-@click.option(
-    "--no-metadata",
-    cls=BooleanOption,
-    default=core.get_input("no_metadata", required=False),
-)
-@click.option(
-    "--dirty", cls=BooleanOption, default=core.get_input("dirty", required=False)
-)
-@click.option(
-    "--tagged-metadata",
-    cls=BooleanOption,
-    default=core.get_input("tagged_metadata", required=False),
-)
-@click.option("--pattern", default=core.get_input("pattern", required=False))
-@click.option("--format", default=core.get_input("format", required=False))
-@click.option("--style", default=core.get_input("style", required=False))
-@click.option(
-    "--latest-tag",
-    cls=BooleanOption,
-    default=core.get_input("latest_tag", required=False),
-)
-@click.option(
-    "--bump", cls=BooleanOption, default=core.get_input("bump", required=False)
-)
-@click.option("--tag-dir", default=core.get_input("tag_dir", required=False))
-@click.option(
-    "--is-postrelease",
-    cls=BooleanOption,
-    default=core.get_input("is_postrelease", required=False),
-)
-def cli(
-    vcs,
-    metadata,
-    no_metadata,
-    dirty,
-    tagged_metadata,
-    pattern,
-    format,
-    style,
-    latest_tag,
-    bump,
-    tag_dir,
-    is_postrelease,
-):
-    import inspect
-
-    from dunamai import Vcs, Version
-    from packaging.version import parse
-
-    core.start_group("Check dynamic version using `dunamai`")
-    kwargs = {}
-    if pattern:
-        kwargs["pattern"] = pattern
-    if latest_tag:
-        kwargs["latest_tag"] = True
-    if tag_dir:
-        kwargs["tag_dir"] = tag_dir
-    print(
-        ">>> dunamai_version = Version.from_vcs(Vcs(%r)%s)"
-        % (
-            vcs,
-            ", "
-            + ", ".join(["{}={!r}".format(key, value) for key, value in kwargs.items()])
-            if len(kwargs)
-            else "",
-        )
-    )
-    dunamai_version = Version.from_vcs(Vcs(vcs), **kwargs)
-    print("Checked version: %s" % dunamai_version)
-    core.end_group()
-
-    core.start_group("Serialize dunamai version")
-    kwargs = {}
-    if metadata:
-        kwargs["metadata"] = True
-    if no_metadata:
-        kwargs["metadata"] = False
-    if dirty:
-        kwargs["dirty"] = dirty
-    if format:
-        kwargs["format"] = format
-    if style:
-        kwargs["style"] = style
-    if bump:
-        kwargs["bump"] = bump
-    if tagged_metadata:
-        kwargs["tagged_metadata"] = tagged_metadata
-    print(
-        ">>> serialized_version = dunamai_version.serialize(%s)"
-        % ", ".join(["{}={!r}".format(key, value) for key, value in kwargs.items()])
-    )
-    serialized_version = dunamai_version.serialize(**kwargs).replace(".dev0", "")
-    print("Serialized version: %s" % serialized_version)
-    core.end_group()
-
-    core.start_group("Analyze the serialized version using `packaging.version.parse()`")
-    packaging_version = parse(serialized_version)
-
-    if packaging_version.is_postrelease and not is_postrelease:
-        print(
-            "Detected version is in postrelease format but prerelease format is desired"
-        )
-        print("Bumping version to be a prerelease format")
-        kwargs["bump"] = True
-        serialized_version = dunamai_version.serialize(**kwargs).replace(".dev0", "")
-        print(
-            ">>> serialized_version = dunamai_version.serialize(%s)"
-            % ", ".join(["{}={!r}".format(key, value) for key, value in kwargs.items()])
-        )
-        print("Bumped version: %s" % serialized_version)
-        packaging_version = parse(serialized_version)
-
-    outputs = {}
-    outputs["version"] = "%s" % packaging_version
-    outputs["is_finalrelease"] = (
-        not packaging_version.is_prerelease
-        and not packaging_version.is_devrelease
-        and not packaging_version.is_postrelease
-    )
-    attributes = [
-        (attr, value)
-        for attr, value in inspect.getmembers(packaging_version)
-        if not attr.startswith("_")
-    ]
-    for attr, value in attributes:
-        outputs[attr] = value
-    core.end_group()
-
-    core.start_group("Analyzed version attributes")
-    for attr, value in outputs.items():
-        print("{}: {}".format(attr, value))
-    core.end_group()
-
-    for attr, value in outputs.items():
-        core.set_output(attr, value)
-
-
-def main():
-    cli()  # pylint: disable=no-value-for-parameter
-
-
-if __name__ == "__main__":
-    main()
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index b2aaf227..00000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
-version: 2
-updates:
-  - package-ecosystem: "github-actions" # See documentation for possible values
-    directory: "/" # Location of package manifests
-    schedule:
-      interval: "daily"
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
deleted file mode 100644
index 66242cd2..00000000
--- a/.github/release-drafter.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-template: |
-  # What's Changed
-
-  $CHANGES
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 5c60678b..00000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-name: CI
-
-on:
-  push:
-    branches:
-    - master
-  pull_request:
-    branches:
-    - master
-  workflow_dispatch:
-    inputs:
-
-jobs:
-  build-and-test:
-
-    runs-on: ${{ matrix.os }}
-    strategy:
-      matrix:
-        os: [ubuntu-latest, windows-latest, macos-latest]
-        python-version: [3.8, 3.9]
-        architecture: [x86, x64]
-        exclude:
-        - os: ubuntu-latest
-        - os: macos-latest
-
-    steps:
-    - uses: actions/checkout@v3
-    - name: Set up Python
-      uses: actions/setup-python@v4
-      id: setup-python
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Install poetry
-      run: |
-        python -m pip install --upgrade pip
-        pip install pipx
-        pipx install poetry
-    - name: Get poetry cache dir
-      id: poetry-cache
-      run: |
-        echo "::set-output name=dir::$(poetry config cache-dir)"
-    - name: Restore cache
-      uses: actions/cache@v3
-      with:
-        path: ${{ steps.poetry-cache.outputs.dir }}
-        key: ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-${{ matrix.architecture }}-${{ hashFiles('poetry.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-${{ matrix.architecture }}-
-    - name: Install dependencies
-      run: |
-        poetry install
-    - name: Test with pytest
-      run: |
-        poetry run pytest -n auto --dist loadscope --junit-xml=junit/test-results.xml --cov --cov-report=xml --cov-report=html
-    - name: Update Codecov coverage report
-      uses: codecov/codecov-action@v3.1.1
-      with:
-        token: ${{ secrets.CODECOV_TOKEN }}
-        flags: ${{ matrix.os }}-py${{ matrix.python-version }}
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
deleted file mode 100644
index 8941ecc2..00000000
--- a/.github/workflows/documentation.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: Documentation
-
-on:
-  push:
-    branches:
-    - master
-    paths:
-    - '**.rst'
-    - 'docs/*'
-    - '.github/workflows/documentation.yml'
-  workflow_dispatch:
-    inputs:
-      force_orphan:
-        description: Force orphan
-        required: false
-        default: false
-
-jobs:
-  build-and-publish:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Set up Python
-      uses: actions/setup-python@v4
-      id: setup-python
-      with:
-        python-version: 3.8
-    - name: Install poetry
-      run: |
-        python -m pip install --upgrade pip
-        pip install pipx
-        pipx install poetry
-    - name: Get poetry cache dir
-      id: poetry-cache
-      run: |
-        echo "::set-output name=dir::$(poetry config cache-dir)"
-    - name: Restore cache
-      uses: actions/cache@v3
-      with:
-        path: ${{ steps.poetry-cache.outputs.dir }}
-        key: ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-x64-${{ hashFiles('poetry.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-x64-
-    - name: Install dependencies
-      run: |
-        poetry install
-        sudo apt-get update && sudo apt-get install pandoc
-    - name: Build documentation
-      run: |
-        poetry run make -C docs html
-    - name: Publish documentaion to Github Pages
-      uses: peaceiris/actions-gh-pages@v3
-      with:
-        github_token: ${{ secrets.GITHUB_TOKEN }}
-        publish_dir: ./docs/build/html/
-        force_orphan: ${{ github.event.inputs.force_orphan }}
-        commit_message: ${{ github.event.head_commit.message }}
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
deleted file mode 100644
index b9a391ed..00000000
--- a/.github/workflows/release-drafter.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: Draft release
-
-on:
-  push:
-    branches:
-    - master
-  create:
-    branches:
-    - master
-    tags:
-    - 'v[0-9]**'
-  workflow_dispatch:
-    inputs:
-      is_postrelease:
-        description: Whether this release is postrelease (default is prerelease)
-        required: true
-        default: false
-
-jobs:
-  draft-release:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-      with:
-        ref: ${{ github.event.create.ref }}
-        fetch-depth: 0
-    - name: Check version
-      id: check-version
-      uses: ./.github/actions/check-version
-      with:
-        is_postrelease: ${{ github.event.inputs.is_postrelease }}
-    - name: Draft release
-      id: draft-release
-      uses: release-drafter/release-drafter@v5
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      with:
-        name: v${{ steps.check-version.outputs.version }}
-        tag: v${{ steps.check-version.outputs.version }}
-        version: ${{ steps.check-version.outputs.version }}
-        publish: ${{ steps.check-version.outputs.is_finalrelease }}
-        prerelease: ${{ steps.check-version.outputs.is_prerelease }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 61332c59..00000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,114 +0,0 @@
-name: Publish Python distribution to PyPI
-
-on:
-  release:
-    types:
-    - published
-  workflow_dispatch:
-    inputs:
-      new_version:
-        description: New version number
-        required: true
-      skip_test_pypi_publish:
-        desctiption: Skip publish to test PyPI
-        required: false
-        default: false
-      skip_pypi_publish:
-        desctiption: Skip publish to PyPI
-        required: false
-        default: false
-
-jobs:
-  build-and-publish:
-    runs-on: windows-latest
-    steps:
-    - uses: actions/checkout@v3
-      with:
-        ref: ${{ github.event.release.tag_name }}
-        fetch-depth: 0
-    - name: Set up Python
-      uses: actions/setup-python@v4
-      id: setup-python
-      with:
-        python-version: 3.8
-    - name: Install poetry
-      run: |
-        python -m pip install --upgrade pip
-        pip install pipx
-        pipx install poetry
-    - name: Get poetry cache dir
-      id: poetry-cache
-      run: |
-        echo "::set-output name=dir::$(poetry config cache-dir)"
-    - name: Restore cache
-      uses: actions/cache@v3
-      with:
-        path: ${{ steps.poetry-cache.outputs.dir }}
-        key: ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-x64-${{ hashFiles('poetry.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-poetry-py${{ steps.setup-python.outputs.python-version }}-x64-
-    - name: Install dependencies
-      run: |
-        poetry install
-    - name: Check version
-      uses: actions/github-script@v6
-      id: check-version
-      with:
-        script: |
-          const version = (() => {
-            if (context.payload.release) {
-              return context.payload.release.tag_name.slice(1)
-            } else if (context.payload.inputs) {
-              return context.payload.inputs.new_version
-            } else {
-              throw 'Cannot check version to publish'
-            }
-          })()
-          core.setOutput('version', version)
-    - name: Bump version
-      run: |
-        poetry run bump2version --no-commit --no-tag --allow-dirty --new-version=0 patch
-        poetry run bump2version --no-commit --no-tag --allow-dirty --new-version=${{ steps.check-version.outputs.version }} patch
-    - name: Build
-      run: |
-        poetry build
-    - name: Publish distribution to Test PyPI
-      uses: pypa/gh-action-pypi-publish@release/v1
-      with:
-        password: ${{ secrets.TEST_PYPI_TOKEN }}
-        repository_url: https://test.pypi.org/legacy/
-        skip_existing: true
-      if: ${{ github.event.inputs.skip_test_pypi_publish != 'true' && runner.os != 'Windows' }}
-    - name: Publish distribution to Test PyPI
-      shell: bash
-      env:
-        POETRY_PYPI_TOKEN_PYPI_TEST: ${{ secrets.TEST_PYPI_TOKEN }}
-      run: |
-        poetry config repositories.pypi-test https://test.pypi.org/legacy/
-        poetry config pypi-token.pypi-test ${POETRY_PYPI_TOKEN_PYPI_TEST}
-        poetry publish -n -r pypi-test
-      if: ${{ github.event.inputs.skip_test_pypi_publish != 'true' && runner.os == 'Windows' }}
-    - name: Install from test and test running
-      run: |
-        pip install --extra-index-url https://test.pypi.org/simple koapy
-        python -c 'import koapy;print(koapy.__version__)'
-        pip uninstall -y koapy
-      if: ${{ github.event.inputs.skip_test_pypi_publish != 'true' }}
-    - name: Publish distribution to PyPI
-      uses: pypa/gh-action-pypi-publish@release/v1
-      with:
-        password: ${{ secrets.PYPI_TOKEN }}
-      if: ${{ github.event.inputs.skip_pypi_publish != 'true' && runner.os != 'Windows' }}
-    - name: Publish distribution to PyPI
-      shell: bash
-      env:
-        POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
-      run: |
-        poetry config pypi-token.pypi ${POETRY_PYPI_TOKEN_PYPI}
-        poetry publish -n
-      if: ${{ github.event.inputs.skip_pypi_publish != 'true' && runner.os == 'Windows' }}
-    - name: Install and test running
-      run: |
-        pip install koapy
-        python -c 'import koapy;print(koapy.__version__)'
-      if: ${{ github.event.inputs.skip_pypi_publish != 'true' }}
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index fc3f7ea7..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,161 +0,0 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-wheels/
-share/python-wheels/
-*.egg-info/
-.installed.cfg
-*.egg
-MANIFEST
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.nox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-
-# Flask stuff:
-instance/
-.webassets-cache
-
-# Scrapy stuff:
-.scrapy
-
-# Sphinx documentation
-docs/_build/
-docs/build/
-docs/source/autoapi/
-
-# PyBuilder
-.pybuilder/
-target/
-
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-#   For a library or package, you might want to ignore these files since the code is
-#   intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-#   However, in case of collaboration, if having platform-specific dependencies or dependencies
-#   having no cross-platform support, pipenv may install dependencies that don't work, or not
-#   install all needed dependencies.
-#Pipfile.lock
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Cython debug symbols
-cython_debug/
-
-# IDE settings
-.vscode/
-
-# PyPi
-.pypirc
-
-# Mac OS
-.DS_Store
-
-# Other
-/manuals
-
-# config
-koapy.conf
-.koapy.confg
-
-# SSL/TLS credentials files
-*.pem
-*.crt
-*.key
\ No newline at end of file
diff --git a/.isort.cfg b/.isort.cfg
deleted file mode 100644
index 25284d03..00000000
--- a/.isort.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[settings]
-profile = black
-multi_line_output = 3
-lines_between_types = 1
-extend_skip_glob = *_pb2.py,*_pb2_grpc.py
diff --git a/.mypy.ini b/.mypy.ini
deleted file mode 100644
index 976ba029..00000000
--- a/.mypy.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[mypy]
-ignore_missing_imports = True
diff --git a/docs/source/_templates/.gitkeep b/.nojekyll
similarity index 100%
rename from docs/source/_templates/.gitkeep
rename to .nojekyll
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
deleted file mode 100644
index b5f165d7..00000000
--- a/.pre-commit-config.yaml
+++ /dev/null
@@ -1,59 +0,0 @@
-# See https://pre-commit.com/ for usage and config
-repos:
-- repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v3.4.0
-  hooks:
-  - id: check-yaml
-  - id: check-toml
-- repo: local
-  hooks:
-  - id: pyupgrade
-    name: pyupgrade
-    stages: [commit]
-    language: system
-    entry: poetry run pyupgrade --keep-runtime-typing
-    types: [python]
-  - id: isort
-    name: isort
-    stages: [commit]
-    language: system
-    entry: poetry run isort
-    types_or: [cython, pyi, python]
-    args: [--filter-files]
-    require_serial: true
-  - id: black
-    name: black
-    stages: [commit]
-    language: system
-    entry: poetry run black
-    types_or: [python, pyi]
-    require_serial: true
-  - id: flake8
-    name: flake8
-    stages: [manual]
-    language: system
-    entry: poetry run flake8
-    types: [python]
-    require_serial: true
-  - id: pylint
-    name: pylint
-    stages: [manual]
-    language: system
-    entry: poetry run pylint
-    types: [python]
-    args: [--errors-only]
-    require_serial: true
-  - id: mypy
-    name: mypy
-    stages: [manual]
-    language: system
-    entry: poetry run mypy
-    types: [python]
-    require_serial: true
-  - id: pytest
-    name: pytest
-    stages: [push]
-    language: system
-    entry: poetry run pytest --cov
-    types: [python]
-    pass_filenames: false
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index 503d3e7a..00000000
--- a/.pylintrc
+++ /dev/null
@@ -1,613 +0,0 @@
-[MAIN]
-
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
-# Load and enable all available extensions. Use --list-extensions to see a list
-# all available extensions.
-#enable-all-extensions=
-
-# In error mode, messages with a category besides ERROR or FATAL are
-# suppressed, and no reports are done by default. Error mode is compatible with
-# disabling specific errors.
-#errors-only=
-
-# Always return a 0 (non-error) status code, even if lint errors are found.
-# This is primarily useful in continuous integration scripts.
-#exit-zero=
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code.
-extension-pkg-allow-list=PySide2,PyQt5,win32api
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
-# for backward compatibility.)
-extension-pkg-whitelist=
-
-# Return non-zero exit code if any of these messages/categories are detected,
-# even if score is above --fail-under value. Syntax same as enable. Messages
-# specified are enabled, while categories only check already-enabled messages.
-fail-on=
-
-# Specify a score threshold to be exceeded before program exits with error.
-fail-under=10
-
-# Interpret the stdin as a python script, whose filename needs to be passed as
-# the module_or_package argument.
-#from-stdin=
-
-# Files or directories to be skipped. They should be base names, not paths.
-ignore=CVS
-
-# Add files or directories matching the regex patterns to the ignore-list. The
-# regex matches against paths and can be in Posix or Windows format.
-ignore-paths=
-
-# Files or directories matching the regex patterns are skipped. The regex
-# matches against base names, not paths. The default value ignores Emacs file
-# locks
-ignore-patterns=
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis). It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=pythoncom,pywintypes,curses,*_pb2,*_pb2_grpc
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
-# number of processors available to use, and will cap the count on Windows to
-# avoid hangs.
-jobs=1
-
-# Control the amount of potential inferred values when inferring a single
-# object. This can help the performance when dealing with large functions or
-# complex, nested conditions.
-limit-inference-results=100
-
-# List of plugins (as comma separated values of python module names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# Minimum Python version to use for version dependent checks. Will default to
-# the version used to run pylint.
-py-version=3.9
-
-# Discover python modules and packages in the file system subtree.
-recursive=no
-
-# When enabled, pylint would attempt to guess common misconfiguration and emit
-# user-friendly hints instead of false-positive error messages.
-suggestion-mode=yes
-
-# Allow loading of arbitrary C extensions. Extensions are imported into the
-# active Python interpreter and may run arbitrary code.
-unsafe-load-any-extension=no
-
-# In verbose mode, extra non-checker-related info will be displayed.
-#verbose=
-
-
-[REPORTS]
-
-# Python expression which should return a score less than or equal to 10. You
-# have access to the variables 'fatal', 'error', 'warning', 'refactor',
-# 'convention', and 'info' which contain the number of messages in each
-# category, as well as 'statement' which is the total number of statements
-# analyzed. This score is used by the global evaluation report (RP0004).
-evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details.
-msg-template=
-
-# Set the output format. Available formats are text, parseable, colorized, json
-# and msvs (visual studio). You can also give a reporter class, e.g.
-# mypackage.mymodule.MyReporterClass.
-#output-format=
-
-# Tells whether to display a full report or only the messages.
-reports=no
-
-# Activate the evaluation score.
-score=yes
-
-
-[MESSAGES CONTROL]
-
-# Only show warnings with the listed confidence levels. Leave empty to show
-# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
-# UNDEFINED.
-confidence=HIGH,
-           CONTROL_FLOW,
-           INFERENCE,
-           INFERENCE_FAILURE,
-           UNDEFINED
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once). You can also use "--disable=all" to
-# disable everything first and then re-enable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use "--disable=all --enable=classes
-# --disable=W".
-disable=raw-checker-failed,
-        bad-inline-option,
-        locally-disabled,
-        file-ignored,
-        suppressed-message,
-        useless-suppression,
-        deprecated-pragma,
-        use-symbolic-message-instead,
-        assignment-from-no-return,
-        pointless-string-statement,
-        protected-access,
-        useless-parent-delegation
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once). See also the "--disable" option for examples.
-enable=c-extension-no-member
-
-
-[BASIC]
-
-# Naming style matching correct argument names.
-argument-naming-style=snake_case
-
-# Regular expression matching correct argument names. Overrides argument-
-# naming-style. If left empty, argument names will be checked with the set
-# naming style.
-#argument-rgx=
-
-# Naming style matching correct attribute names.
-attr-naming-style=snake_case
-
-# Regular expression matching correct attribute names. Overrides attr-naming-
-# style. If left empty, attribute names will be checked with the set naming
-# style.
-#attr-rgx=
-
-# Bad variable names which should always be refused, separated by a comma.
-bad-names=foo,
-          bar,
-          baz,
-          toto,
-          tutu,
-          tata
-
-# Bad variable names regexes, separated by a comma. If names match any regex,
-# they will always be refused
-bad-names-rgxs=
-
-# Naming style matching correct class attribute names.
-class-attribute-naming-style=any
-
-# Regular expression matching correct class attribute names. Overrides class-
-# attribute-naming-style. If left empty, class attribute names will be checked
-# with the set naming style.
-#class-attribute-rgx=
-
-# Naming style matching correct class constant names.
-class-const-naming-style=UPPER_CASE
-
-# Regular expression matching correct class constant names. Overrides class-
-# const-naming-style. If left empty, class constant names will be checked with
-# the set naming style.
-#class-const-rgx=
-
-# Naming style matching correct class names.
-class-naming-style=PascalCase
-
-# Regular expression matching correct class names. Overrides class-naming-
-# style. If left empty, class names will be checked with the set naming style.
-#class-rgx=
-
-# Naming style matching correct constant names.
-const-naming-style=UPPER_CASE
-
-# Regular expression matching correct constant names. Overrides const-naming-
-# style. If left empty, constant names will be checked with the set naming
-# style.
-#const-rgx=
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-# Naming style matching correct function names.
-function-naming-style=snake_case
-
-# Regular expression matching correct function names. Overrides function-
-# naming-style. If left empty, function names will be checked with the set
-# naming style.
-#function-rgx=
-
-# Good variable names which should always be accepted, separated by a comma.
-good-names=i,
-           j,
-           k,
-           ex,
-           Run,
-           _
-
-# Good variable names regexes, separated by a comma. If names match any regex,
-# they will always be accepted
-good-names-rgxs=
-
-# Include a hint for the correct naming format with invalid-name.
-include-naming-hint=no
-
-# Naming style matching correct inline iteration names.
-inlinevar-naming-style=any
-
-# Regular expression matching correct inline iteration names. Overrides
-# inlinevar-naming-style. If left empty, inline iteration names will be checked
-# with the set naming style.
-#inlinevar-rgx=
-
-# Naming style matching correct method names.
-method-naming-style=snake_case
-
-# Regular expression matching correct method names. Overrides method-naming-
-# style. If left empty, method names will be checked with the set naming style.
-#method-rgx=
-
-# Naming style matching correct module names.
-module-naming-style=snake_case
-
-# Regular expression matching correct module names. Overrides module-naming-
-# style. If left empty, module names will be checked with the set naming style.
-#module-rgx=
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=^_
-
-# List of decorators that produce properties, such as abc.abstractproperty. Add
-# to this list to register other decorators that produce valid properties.
-# These decorators are taken in consideration only for invalid-name.
-property-classes=abc.abstractproperty
-
-# Regular expression matching correct type variable names. If left empty, type
-# variable names will be checked with the set naming style.
-#typevar-rgx=
-
-# Naming style matching correct variable names.
-variable-naming-style=snake_case
-
-# Regular expression matching correct variable names. Overrides variable-
-# naming-style. If left empty, variable names will be checked with the set
-# naming style.
-#variable-rgx=
-
-
-[CLASSES]
-
-# Warn about protected attribute access inside special methods
-check-protected-access-in-special-methods=no
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,
-                      __new__,
-                      setUp,
-                      __post_init__
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,
-                  _fields,
-                  _replace,
-                  _source,
-                  _make
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=cls
-
-
-[DESIGN]
-
-# List of regular expressions of class ancestor names to ignore when counting
-# public methods (see R0903)
-exclude-too-few-public-methods=
-
-# List of qualified class names to ignore when counting class parents (see
-# R0901)
-ignored-parents=
-
-# Maximum number of arguments for function / method.
-max-args=5
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Maximum number of boolean expressions in an if statement (see R0916).
-max-bool-expr=5
-
-# Maximum number of branch for function / method body.
-max-branches=12
-
-# Maximum number of locals for function / method body.
-max-locals=15
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-# Maximum number of return / yield for function / method body.
-max-returns=6
-
-# Maximum number of statements in function / method body.
-max-statements=50
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when caught.
-overgeneral-exceptions=BaseException,
-                       Exception
-
-
-[FORMAT]
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )??$
-
-# Number of spaces of indent required inside a hanging or continued line.
-indent-after-paren=4
-
-# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
-# tab).
-indent-string='    '
-
-# Maximum number of characters on a single line.
-max-line-length=88
-
-# Maximum number of lines in a module.
-max-module-lines=1000
-
-# Allow the body of a class to be on the same line as the declaration if body
-# contains single statement.
-single-line-class-stmt=no
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-
-[IMPORTS]
-
-# List of modules that can be imported at any level, not just the top level
-# one.
-allow-any-import-level=
-
-# Allow wildcard imports from modules that define __all__.
-allow-wildcard-with-all=no
-
-# Deprecated modules which should not be used, separated by a comma.
-deprecated-modules=
-
-# Output a graph (.gv or any supported image format) of external dependencies
-# to the given file (report RP0402 must not be disabled).
-ext-import-graph=
-
-# Output a graph (.gv or any supported image format) of all (i.e. internal and
-# external) dependencies to the given file (report RP0402 must not be
-# disabled).
-import-graph=
-
-# Output a graph (.gv or any supported image format) of internal dependencies
-# to the given file (report RP0402 must not be disabled).
-int-import-graph=
-
-# Force import order to recognize a module as part of the standard
-# compatibility libraries.
-known-standard-library=
-
-# Force import order to recognize a module as part of a third party library.
-known-third-party=enchant
-
-# Couples of modules and preferred modules, separated by a comma.
-preferred-modules=
-
-
-[LOGGING]
-
-# The type of string formatting that logging methods do. `old` means using %
-# formatting, `new` is for `{}` formatting.
-logging-format-style=old
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format.
-logging-modules=logging
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,
-      XXX,
-      TODO
-
-# Regular expression of note tags to take in consideration.
-notes-rgx=
-
-
-[REFACTORING]
-
-# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
-
-# Complete name of functions that never returns. When checking for
-# inconsistent-return-statements if a never returning function is called then
-# it will be considered as an explicit return statement and no message will be
-# printed.
-never-returning-functions=sys.exit,argparse.parse_error
-
-
-[SIMILARITIES]
-
-# Comments are removed from the similarity computation
-ignore-comments=yes
-
-# Docstrings are removed from the similarity computation
-ignore-docstrings=yes
-
-# Imports are removed from the similarity computation
-ignore-imports=yes
-
-# Signatures are removed from the similarity computation
-ignore-signatures=yes
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-
-[SPELLING]
-
-# Limits count of emitted suggestions for spelling mistakes.
-max-spelling-suggestions=4
-
-# Spelling dictionary name. Available dictionaries: none. To make it work,
-# install the 'python-enchant' package.
-spelling-dict=
-
-# List of comma separated words that should be considered directives if they
-# appear at the beginning of a comment and should not be checked.
-spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains the private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to the private dictionary (see the
-# --spelling-private-dict-file option) instead of raising a message.
-spelling-store-unknown-words=no
-
-
-[STRING]
-
-# This flag controls whether inconsistent-quotes generates a warning when the
-# character used as a quote delimiter is used inconsistently within a module.
-check-quote-consistency=no
-
-# This flag controls whether the implicit-str-concat should generate a warning
-# on implicit string concatenation in sequences defined over several lines.
-check-str-concat-over-line-jumps=no
-
-
-[TYPECHECK]
-
-# List of decorators that produce context managers, such as
-# contextlib.contextmanager. Add to this list to register other decorators that
-# produce valid context managers.
-contextmanager-decorators=contextlib.contextmanager
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-# Tells whether to warn about missing members when the owner of the attribute
-# is inferred to be None.
-ignore-none=yes
-
-# This flag controls whether pylint should warn about no-member and similar
-# checks whenever an opaque object is returned when inferring. The inference
-# can return multiple potential results while evaluating a Python object, but
-# some branches might not be evaluated, which results in partial inference. In
-# that case, it might be useful to still emit no-member and other checks for
-# the rest of the inferred objects.
-ignore-on-opaque-inference=yes
-
-# List of symbolic message names to ignore for Mixin members.
-ignored-checks-for-mixins=no-member,
-                          not-async-context-manager,
-                          not-context-manager,
-                          attribute-defined-outside-init
-
-# List of class names for which member attributes should not be checked (useful
-# for classes with dynamically set attributes). This supports the use of
-# qualified names.
-ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
-
-# Show a hint with possible names when a member name was not found. The aspect
-# of finding the hint is based on edit distance.
-missing-member-hint=yes
-
-# The minimum edit distance a name should have in order to be considered a
-# similar match for a missing member name.
-missing-member-hint-distance=1
-
-# The total number of similar names that should be taken in consideration when
-# showing a hint for a missing member.
-missing-member-max-choices=1
-
-# Regex pattern to define which classes are considered mixins.
-mixin-class-rgx=.*[Mm]ixin
-
-# List of decorators that change the signature of a decorated function.
-signature-mutators=
-
-
-[VARIABLES]
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid defining new builtins when possible.
-additional-builtins=
-
-# Tells whether unused global variables should be treated as a violation.
-allow-global-unused-variables=yes
-
-# List of names allowed to shadow builtins
-allowed-redefined-builtins=
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,_cb
-
-# A regular expression matching the name of dummy variables (i.e. expected to
-# not be used).
-dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore.
-ignored-argument-names=_.*|^ignored_|^unused_
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# List of qualified module names which can have objects that can redefine
-# builtins.
-redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
diff --git a/.pyup.yml b/.pyup.yml
deleted file mode 100644
index 39498c15..00000000
--- a/.pyup.yml
+++ /dev/null
@@ -1 +0,0 @@
-update: false
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
deleted file mode 100644
index 80abd059..00000000
--- a/.readthedocs.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-# .readthedocs.yaml
-# Read the Docs configuration file
-# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
-
-# Required
-version: 2
-
-# Build documentation in the docs/ directory with Sphinx
-sphinx:
-  builder: html
-  configuration: docs/source/conf.py
-  fail_on_warning: false
-
-# Optionally build your docs in additional formats such as PDF
-formats:
-- htmlzip
-
-# Optionally set the version of Python and requirements required to build your docs
-python:
-  version: 3.8
-  install:
-  - method: pip
-    path: .
-  - requirements: requirements_dev.txt
-  system_packages: true
diff --git a/AUTHORS.rst b/AUTHORS.rst
deleted file mode 100644
index d6b30fb8..00000000
--- a/AUTHORS.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-=======
-Credits
-=======
-
-Development Lead
-----------------
-
-* Yunseong Hwang as `elbakramer`_ 
-
-.. _`elbakramer`: https://github.com/elbakramer
-
-Contributors
-------------
-
-* Dongyoon Han as `dani-han`_
-* `resoliwan`_
-* Taehoon Lee as `taehoon1`_
-
-.. _`dani-han`: https://github.com/dani-han
-.. _`resoliwan`: https://github.com/resoliwan
-.. _`taehoon1`: https://github.com/taehoon1
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
deleted file mode 100644
index cca5b3e5..00000000
--- a/CONTRIBUTING.rst
+++ /dev/null
@@ -1,167 +0,0 @@
-============
-Contributing
-============
-
-Contributions are welcome, and they are greatly appreciated! Every little bit
-helps, and credit will always be given.
-
-You can contribute in many ways:
-
-Types of Contributions
-----------------------
-
-Report Bugs
-~~~~~~~~~~~
-
-Report bugs at https://github.com/elbakramer/koapy/issues.
-
-If you are reporting a bug, please include:
-
-* Your operating system name and version.
-* Any details about your local setup that might be helpful in troubleshooting.
-* Detailed steps to reproduce the bug.
-
-Fix Bugs
-~~~~~~~~
-
-Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
-wanted" is open to whoever wants to implement it.
-
-Implement Features
-~~~~~~~~~~~~~~~~~~
-
-Look through the GitHub issues for features. Anything tagged with "enhancement"
-and "help wanted" is open to whoever wants to implement it.
-
-Write Documentation
-~~~~~~~~~~~~~~~~~~~
-
-KOAPY could always use more documentation, whether as part of the
-official KOAPY docs, in docstrings, or even on the web in blog posts,
-articles, and such.
-
-Submit Feedback
-~~~~~~~~~~~~~~~
-
-The best way to send feedback is to file an issue at https://github.com/elbakramer/koapy/issues.
-
-If you are proposing a feature:
-
-* Explain in detail how it would work.
-* Keep the scope as narrow as possible, to make it easier to implement.
-* Remember that this is a volunteer-driven project, and that contributions
-  are welcome :)
-
-Get Started!
-------------
-
-Ready to contribute? Here's how to set up `koapy` for local development.
-
-1. Fork the `koapy` repo on GitHub.
-
-2. Clone your fork locally:
-
-   .. code-block:: console
-
-       $ git clone https://github.com/your_name_here/koapy.git
-
-3. Set up your fork for local development:
-
-   .. code-block:: console
-
-       $ # Install poetry if you don't have one:
-       $ # https://python-poetry.org/docs/#installation
-
-       $ # Example below will install poetry using pipx
-
-       $ # Install ``pipx``
-       $ pip install pipx
-       $ pipx ensurepath
-
-       $ # Install ``poetry`` using ``pipx``
-       $ pipx install poetry
-
-       $ # Run ``poetry install`` to install dependencies
-       $ cd koapy/
-       $ poetry install
-
-       $ # Install ``pre-commit`` hooks
-       $ poetry run pre-commit install
-
-   When you run ``poetry install``, all the dependencies including development tools will be installed under a virtualenv managed by poetry.
-
-   Then you can run those commands using ``poetry run command args...``, like the last command in the example above.
-
-4. Create a branch for local development:
-
-   .. code-block:: console
-
-       $ git checkout -b name-of-your-bugfix-or-feature
-
-   Now you can make your changes locally.
-
-5. When you're done making changes, you can check if your changes pass some checks:
-
-   .. code-block:: console
-
-       $ # Code formatters
-       $ poetry run isort .
-       $ poetry run black .
-
-       $ # Linters and Static analysis tools
-       $ poetry run flake8 koapy tests
-       $ poetry run pylint koapy tests
-       $ poetry run mypy koapy tests
-
-       $ # Testing
-       $ poetry run pytest --cov
-
-   Or you can just commit/push your changes to make pre-commit hooks trigger those checks automatically.
-   If you want to skip those hooks temporarily, add `--no-verify` option for git commit/push.
-
-6. Commit your changes and push your branch to GitHub:
-
-   .. code-block:: console
-
-       $ git add .
-       $ git commit -m "Your detailed description of your changes."
-       $ git push origin name-of-your-bugfix-or-feature
-
-7. Submit a pull request through the GitHub website.
-
-Pull Request Guidelines
------------------------
-
-Before you submit a pull request, check that it meets these guidelines:
-
-1. The pull request should include tests.
-2. If the pull request adds functionality, the docs should be updated. Put
-   your new functionality into a function with a docstring, and add the
-   feature to the list in README.rst.
-3. The pull request should work for Python 3.8 and 3.9. Check
-   https://github.com/elbakramer/koapy/actions/workflows/ci.yml
-   and make sure that the tests pass for all supported Python versions.
-
-Tips
-----
-
-To run a subset of tests:
-
-.. code-block:: console
-
-    $ pytest tests.test_koapy
-
-Deploying
----------
-
-A reminder for the maintainers on how to deploy.
-Make sure all your changes are committed (including an entry in HISTORY.rst).
-Then run:
-
-.. code-block:: console
-
-    $ poetry run bump2version patch  # possible: major / minor / patch
-    $ git push
-    $ git push --follow-tags
-
-Travis will then deploy to PyPI if tests pass.
diff --git a/HISTORY.rst b/HISTORY.rst
deleted file mode 100644
index e99bbd99..00000000
--- a/HISTORY.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-=======
-History
-=======
-
-0.7.1 (2022-02-07)
-------------------
-
-* Latest release on PyPI.
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index e329dc3e..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Yunseong Hwang
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/LICENSE.APACHE-2.0 b/LICENSE.APACHE-2.0
deleted file mode 100644
index 261eeb9e..00000000
--- a/LICENSE.APACHE-2.0
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/LICENSE.GPL-3.0-OR-LATER b/LICENSE.GPL-3.0-OR-LATER
deleted file mode 100644
index f288702d..00000000
--- a/LICENSE.GPL-3.0-OR-LATER
+++ /dev/null
@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. 
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    
-    Copyright (C)   
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-      Copyright (C)   
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-.
diff --git a/LICENSE.MIT b/LICENSE.MIT
deleted file mode 100644
index e329dc3e..00000000
--- a/LICENSE.MIT
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Yunseong Hwang
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index d25f0cbe..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,14 +0,0 @@
-include AUTHORS.rst
-include CONTRIBUTING.rst
-include HISTORY.rst
-include LICENSE
-include LICENSE.MIT
-include LICENSE.APACHE-2.0
-include LICENSE.GPL-3.0-OR-LATER
-include README.rst
-
-recursive-include tests *
-recursive-exclude * __pycache__
-recursive-exclude * *.py[co]
-
-recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 6daed5ee..00000000
--- a/README.rst
+++ /dev/null
@@ -1,1139 +0,0 @@
-=====
-KOAPY
-=====
-
-.. container::
-
-    .. image:: https://img.shields.io/pypi/v/koapy.svg
-            :target: https://pypi.python.org/pypi/koapy
-            :alt: PyPI Version
-
-    .. image:: https://img.shields.io/pypi/pyversions/koapy.svg
-            :target: https://pypi.python.org/pypi/koapy/
-            :alt: PyPI Python Versions
-
-    .. image:: https://img.shields.io/pypi/status/koapy.svg
-            :target: https://pypi.python.org/pypi/koapy/
-            :alt: PyPI Status
-
-    .. badges from below are commendted out
-
-    .. .. image:: https://img.shields.io/pypi/dm/koapy.svg
-            :target: https://pypi.python.org/pypi/koapy/
-            :alt: PyPI Monthly Donwloads
-
-.. container::
-
-    .. image:: https://img.shields.io/github/workflow/status/elbakramer/koapy/CI/master
-            :target: https://github.com/elbakramer/koapy/actions/workflows/ci.yml
-            :alt: CI Build Status
-    .. .. image:: https://github.com/elbakramer/koapy/actions/workflows/ci.yml/badge.svg?branch=master
-
-    .. image:: https://img.shields.io/github/workflow/status/elbakramer/koapy/Documentation/master?label=docs
-            :target: https://elbakramer.github.io/koapy/
-            :alt: Documentation Build Status
-    .. .. image:: https://github.com/elbakramer/koapy/actions/workflows/documentation.yml/badge.svg?branch=master
-
-    .. image:: https://img.shields.io/codecov/c/github/elbakramer/koapy.svg
-            :target: https://codecov.io/gh/elbakramer/koapy
-            :alt: Codecov Coverage
-    .. .. image:: https://codecov.io/gh/elbakramer/koapy/branch/master/graph/badge.svg
-
-    .. image:: https://requires.io/github/elbakramer/koapy/requirements.svg?branch=master
-            :target: https://requires.io/github/elbakramer/koapy/requirements/?branch=master
-            :alt: Requires.io Requirements Status
-
-    .. badges from below are commendted out
-
-    .. .. image:: https://img.shields.io/travis/elbakramer/koapy.svg
-            :target: https://travis-ci.com/elbakramer/koapy
-            :alt: Travis CI Build Status
-    .. .. image:: https://travis-ci.com/elbakramer/koapy.svg?branch=master
-
-    .. .. image:: https://img.shields.io/readthedocs/koapy/latest.svg
-            :target: https://koapy.readthedocs.io/en/latest/?badge=latest
-            :alt: ReadTheDocs Documentation Build Status
-    .. .. image:: https://readthedocs.org/projects/koapy/badge/?version=latest
-
-    .. .. image:: https://pyup.io/repos/github/elbakramer/koapy/shield.svg
-            :target: https://pyup.io/repos/github/elbakramer/koapy/
-            :alt: PyUp Updates
-
-.. container::
-
-    .. image:: https://img.shields.io/pypi/l/koapy.svg
-            :target: https://github.com/elbakramer/koapy/blob/master/LICENSE
-            :alt: PyPI License
-
-    .. badges from below are commendted out
-
-    .. .. image:: https://app.fossa.com/api/projects/git%2Bgithub.com%2Felbakramer%2Fkoapy.svg?type=shield
-            :target: https://app.fossa.com/projects/git%2Bgithub.com%2Felbakramer%2Fkoapy?ref=badge_shield
-            :alt: FOSSA Status
-
-.. container::
-
-    .. image:: https://badges.gitter.im/elbakramer/koapy.svg
-            :target: https://gitter.im/koapy/community
-            :alt: Gitter Chat
-    .. .. image:: https://img.shields.io/gitter/room/elbakramer/koapy.svg
-
-    .. image:: https://img.shields.io/badge/code%20style-black-000000.svg
-            :target: https://github.com/psf/black
-            :alt: Code Style: Black
-
-
-Kiwoom Open Api Plus Python
-
-* Free software: `MIT`_ OR `Apache-2.0`_ OR `GPL-3.0-or-later`_
-* Documentation: https://koapy.readthedocs.io.
-
-.. _`MIT`: https://github.com/elbakramer/koapy/blob/master/LICENSE.MIT
-.. _`Apache-2.0`: https://github.com/elbakramer/koapy/blob/master/LICENSE.APACHE-2.0
-.. _`GPL-3.0-or-later`: https://github.com/elbakramer/koapy/blob/master/LICENSE.GPL-3.0-OR-LATER
-
-
-Introduction
-------------
-
-KOAPY 는 `키움증권의 OpenAPI+`_ 를 Python_ 에서 쉽게 사용할 수 있도록 만든
-라이브러리 패키지 및 툴입니다.
-
-키움에서 제공하는 OpenAPI+ 를 활용하는데 필요한 구체적인 지식들을 전혀 알지 못해도,
-기본적인 Python_ 에 대한 지식만 어느 정도 있다면 쉽게 사용할 수 있도록 하는 것에
-초점을 두었습니다.
-
-예를 들어 Python_ 기준으로 아래와 같은 내용들을 잘 모르더라도 충분히 모든 기능을
-사용할 수 있음을 의미합니다.
-
-* 키움에서 제공하는 OpenAPI+ 의 OCX 라이브러리 구조
-* OCX 를 Python_ 에서 구동하기 위해 PyQt5_/PySide2_ 라이브러리의 |QAxWidget|_ 생성
-* 컨트롤에서 함수 호출을 위해 |dynamicCall|_ 함수 사용
-* 이벤트 처리를 위해 적절한 |signal|_/|slot|_ 설정 및 이벤트 처리
-
-.. _`키움증권의 OpenAPI+`: https://www3.kiwoom.com/nkw.templateFrameSet.do?m=m1408000000
-.. _Python: https://www.python.org/
-
-.. _PyQt5: https://www.riverbankcomputing.com/software/pyqt/
-.. _PySide2: https://doc.qt.io/qtforpython/index.html
-
-.. |QAxWidget| replace:: ``QAxWidget``
-.. _QAxWidget: https://doc.qt.io/qt-5/qaxwidget.html
-.. |dynamicCall| replace:: ``dynamicCall``
-.. _dynamicCall: https://doc.qt.io/qt-5/qaxbase.html#dynamicCall
-.. |signal| replace:: ``signal``
-.. _signal: https://doc.qt.io/qt-5/signalsandslots.html#signals
-.. |slot| replace:: ``slot``
-.. _slot: https://doc.qt.io/qt-5/signalsandslots.html#slots
-
-
-Showcase
---------
-
-테이블 데이터 처리를 위한 pandas 임포트
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> import pandas as pd
-
-엔트리포인트 객체 생성
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> from koapy import KiwoomOpenApiPlusEntrypoint
-
-.. code-block:: python
-
-    >>> entrypoint = KiwoomOpenApiPlusEntrypoint()
-
-키움증권 서버와의 연결 확인 및 로그인 처리
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> entrypoint.IsConnected()
-    False
-    >>> entrypoint.EnsureConnected()
-    True
-    >>> entrypoint.IsConnected()
-    True
-
-종목 리스트 및 종목 코드와 이름 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> code_list = entrypoint.GetCodeListByMarketAsList("0")
-    >>> code_list
-    ['000020', '000040', '000050', '000060', '000070', ...]
-
-.. code-block:: python
-
-    >>> name_list = [entrypoint.GetMasterCodeName(code) for code in code_list]
-    >>> name_list
-    ['동화약품', 'KR모터스', '경방', '메리츠화재', '삼양홀딩스', ...]
-
-.. code-block:: python
-
-    >>> code_by_name = {name: code for code, name in zip(code_list, name_list)}
-
-.. code-block:: python
-
-    >>> name = "삼성전자"
-    >>> code = code_by_name[name]
-    >>> code
-    '005930'
-
-단일 종목의 기본정보 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> info = entrypoint.GetStockBasicInfoAsDict(code)
-    >>> info
-    {'종목코드': '005930', '종목명': '삼성전자', '결산월': '12', '액면가': '100', '자본금': '7780', '상장주식': '5969783', '신용비율': '+0.12', '연중최고': '+79800', '연중최저': '-71200', '시가총액': '4417639', '시가총액비중': '', '외인소진률': '+52.09', '대용가': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '매출액': '2368070', '영업이익': '359939', '당기순이익': '264078', '250최고': '+86400', '250최저': '-68300', '시가': '+74300', '고가': '+74600', '저가': '+73400', '상한가': '+95200', '하한가': '-51400', '기준가': '73300', '예상체결가': '-0', '예상체결수량': '0', '250최고가일': '20210202', '250최고가대비율': '-14.35', '250최저가일': '20211013', '250최저가대비율': '+8.35', '현재가': '+74000', '대비기호': '2', '전일대비': '+700', '등락율': '+0.95', '거래량': '12730034', '거래대비': '-71.74', '액면가단위': '원', '유통주식': '4459119', '유통비율': '74.7'}
-
-복수 종목의 기본정보 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> code_list_info = entrypoint.GetStockQuoteInfoAsDataFrame(code_list)
-    >>> code_list_info
-            종목코드                      종목명     현재가    기준가   전일대비 전일대비기호    등락율  \
-    0     000020                     동화약품  +12450  12300   +150      2  +1.22
-    1     000040                    KR모터스    +810    790    +20      2  +2.53
-    2     000050                       경방  +14450  14200   +250      2  +1.76
-    3     000060                    메리츠화재   49450  49450      0      3   0.00
-    4     000070                    삼양홀딩스  +90700  88400  +2300      2  +2.60
-    ...      ...                      ...     ...    ...    ...    ...    ...
-    1744  580031  KB 인버스 KOSDAQ150 선물 ETN  -10930  10960    -30      5  -0.27
-    1745  580032     KB 레버리지 구리 선물 ETN(H)  -20515  20560    -45      5  -0.22
-    1746  580033   KB 인버스 2X 구리 선물 ETN(H)  +18350  18280    +70      2  +0.38
-    1747  580010         KB Wise 분할매매 ETN  +10820  10770    +50      2  +0.46
-    1748  590018       미래에셋 중국 심천 100 ETN  +18810  18645   +165      2  +0.88
-
-            거래량   거래대금   체결량  ...    ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가  \
-    0     135513   1670  +500  ...  00000000
-    1     230165    186   -10  ...  00000000
-    2       6214     89    97  ...  00000000
-    3     411584  20423    -4  ...  00000000
-    4       9052    813    +5  ...  00000000
-    ...      ...    ...   ...  ...       ...   ...     ...  ..   ... .. .. .. ..
-    1744       2      0    -1  ...  00000000
-    1745       0      0        ...  00000000
-    1746      17      0   +10  ...  00000000
-    1747       0      0        ...  00000000
-    1748       1      0    +1  ...  00000000
-
-        로
-    0
-    1
-    2
-    3
-    4
-    ...  ..
-    1744
-    1745
-    1746
-    1747
-    1748
-
-    [1749 rows x 63 columns]
-
-특정 종목의 차트 데이터 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> chart_data = entrypoint.GetDailyStockDataAsDataFrame(code)
-    >>> chart_data
-            종목코드    현재가       거래량     거래대금        일자     시가     고가     저가 수정주가구분  \
-    0     005930  74000  12730034   941413  20220204  74300  74600  73400
-    1             73300  17744721  1314506  20220203  74900  74900  73300
-    2             73300  21367447  1552586  20220128  71300  73700  71200
-    3             71300  22274777  1603685  20220127  73800  74000  71300
-    4             73300  12976730   955547  20220126  73900  74400  73100
-    ...      ...    ...       ...      ...       ...    ...    ...    ...    ...
-    9797           8010      4970        1  19850109   8240   8240   7950
-    9798           8300     12930        4  19850108   8400   8400   8300
-    9799           8410     11810        3  19850107   8400   8500   8390
-    9800           8390      1660        0  19850105   8400   8440   8390
-    9801           8450      1710        0  19850104   8500   8500   8450
-
-        수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가
-    0
-    1
-    2
-    3
-    4
-    ...   ...   ...   ...  ...     ...  ...
-    9797
-    9798
-    9799
-    9800
-    9801
-
-    [9802 rows x 15 columns]
-
-키움증권의 TR 메타 정보 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> from koapy import KiwoomOpenApiPlusTrInfo
-
-.. code-block:: python
-
-    >>> tr_info_list = KiwoomOpenApiPlusTrInfo.get_trinfo_list()
-
-.. code-block:: python
-
-    >>> data = pd.DataFrame.from_records([(info.tr_code, info.name) for info in tr_info_list], columns=['tr_code', 'name'])
-    >>> data
-          tr_code             name
-    0    opt10001         주식기본정보요청
-    1    opt10059      종목별투자자기관별요청
-    2    opt10087         시간외단일가요청
-    3    opt50037       코스피200지수요청
-    4    opt90005       프로그램매매추이요청
-    ..        ...              ...
-    220  opw20013  계좌미결제청산가능수량조회요청
-    221  opw20014     선옵실시간증거금산출요청
-    222  opw20015    옵션매도주문증거금현황요청
-    223  opw20016      신용융자 가능종목요청
-    224  opw20017        신용융자 가능문의
-
-    [225 rows x 2 columns]
-
-OPT10001 TR 요청 전송 및 응답 처리 (싱글데이터)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> opt10001_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001")
-    >>> opt10001_info
-    KiwoomOpenApiPlusTrInfo('opt10001', '주식기본정보요청', 'STOCK', '', '1', '', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 6, 9001)], '주식기본정보', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('종목명', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('결산월', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('액면가', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('자본금', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('상장주식', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('신용비율', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('연중최고', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('연중최저', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('시가총액', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('시가총액비중', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('외인소진률', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('대용가', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('매출액', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('영업이익', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('당기순이익', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250최고', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250최저', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('시가', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('상한가', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('하한가', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('기준가', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('예상체결가', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('예상체결수량', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250최고가일', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250최고가대비율', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250최저가일', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250최저가대비율', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('현재가', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('대비기호', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('전일대비', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('등락율', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('거래량', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대비', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('액면가단위', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('유통주식', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('유통비율', 840, 20, 1684)], '', [])
-
-    >>> opt10001_info.inputs
-    [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 6, 9001)]
-
-    >>> opt10001_info.single_outputs
-    [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('종목명', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('결산월', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('액면가', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('자본금', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('상장주식', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('신용비율', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('연중최고', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('연중최저', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('시가총액', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('시가총액비중', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('외인소진률', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('대용가', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('매출액', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('영업이익', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('당기순이익', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250최고', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250최저', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('시가', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('상한가', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('하한가', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('기준가', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('예상체결가', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('예상체결수량', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250최고가일', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250최고가대비율', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250최저가일', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250최저가대비율', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('현재가', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('대비기호', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('전일대비', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('등락율', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('거래량', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대비', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('액면가단위', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('유통주식', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('유통비율', 840, 20, 1684)]
-
-    >>> opt10001_info.multi_outputs
-    []
-
-.. code-block:: python
-
-    >>> request_name = "주식기본정보요청"  # 사용자 구분명, 구분가능한 임의의 문자열
-    >>> tr_code = "opt10001"
-    >>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
-    >>> inputs = {
-    ...    "종목코드": "005930",  # 삼성전자 종목코드
-    ... }
-
-    >>> output = {}
-
-    >>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
-    ...     names = event.single_data.names
-    ...     values = event.single_data.values
-    ...     for name, value in zip(names, values):
-    ...         output[name] = value
-
-    >>> output
-    {'종목코드': '005930', '종목명': '삼성전자', '결산월': '12', '액면가': '100', '자본금': '7780', '상장주식': '5969783', '신용비율': '+0.12', '연중최고': '+79800', '연중최저': '-71200', '시가총액': '4417639', '시가총액비중': '', '외인소진률': '+52.09', '대용가': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '매출액': '2368070', '영업이익': '359939', '당기순이익': '264078', '250최고': '+86400', '250최저': '-68300', '시가': '+74300', '고가': '+74600', '저가': '+73400', '상한가': '+95200', '하한가': '-51400', '기준가': '73300', '예상체결가': '-0', '예상체결수량': '0', '250최고가일': '20210202', '250최고가대비율': '-14.35', '250최저가일': '20211013', '250최저가대비율': '+8.35', '현재가': '+74000', '대비기호': '2', '전일대비': '+700', '등락율': '+0.95', '거래량': '12730034', '거래대비': '-71.74', '액면가단위': '원', '유통주식': '4459119', '유통비율': '74.7'}
-
-OPT10081 TR 요청 전송 및 응답 처리 (멀티데이터)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> opt10081_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10081")
-    >>> opt10081_info
-    KiwoomOpenApiPlusTrInfo('opt10081', '주식일봉차트조회요청', 'SCHART', '', '1', '3003', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('기준일자', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 40, 20, 9055)], '주식일봉차트', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001)], '주식일봉차트조회', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('현재가', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('거래량', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대금', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('일자', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('시가', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('수정비율', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('대업종구분', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('소업종구분', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('종목정보', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('수정주가이벤트', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('전일종가', 280, 20, 346)])
-
-    >>> opt10081_info.inputs
-    [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('기준일자', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 40, 20, 9055)]
-
-    >>> opt10081_info.single_outputs
-    [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001)]
-
-    >>> opt10081_info.multi_outputs
-    [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('현재가', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('거래량', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대금', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('일자', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('시가', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('수정비율', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('대업종구분', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('소업종구분', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('종목정보', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('수정주가이벤트', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('전일종가', 280, 20, 346)]
-
-.. code-block:: python
-
-    >>> import datetime
-
-    >>> date = datetime.datetime.now().strftime("%Y%m%d")
-    >>> date
-    '20220206'
-
-.. code-block:: python
-
-    >>> request_name = "주식일봉차트조회요청"  # 사용자 구분명, 구분가능한 임의의 문자열
-    >>> tr_code = "opt10081"
-    >>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
-    >>> inputs = {
-    ...     "종목코드": "005930",  # 삼성전자 종목코드
-    ...     "기준일자": "20220206",  # 가장 최근 날짜의 YYYYMMDD 포맷
-    ...     "수정주가구분": "0",  # 0:일반주가, 1:수정주가
-    ... }
-
-    >>> data_list = []
-
-    >>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
-    ...     columns = event.multi_data.names
-    ...     records = [values.values for values in event.multi_data.values]
-    ...     data = pd.DataFrame.from_records(records, columns=columns)
-    ...     data_list.append(data)
-
-    >>> data = pd.concat(data_list, axis=0).reset_index(drop=True)
-    >>> data
-            종목코드    현재가       거래량     거래대금        일자     시가     고가     저가 수정주가구분  \
-    0     005930  74000  12730034   941413  20220204  74300  74600  73400
-    1             73300  17744721  1314506  20220203  74900  74900  73300
-    2             73300  21367447  1552586  20220128  71300  73700  71200
-    3             71300  22274777  1603685  20220127  73800  74000  71300
-    4             73300  12976730   955547  20220126  73900  74400  73100
-    ...      ...    ...       ...      ...       ...    ...    ...    ...    ...
-    9797           8010      4970        1  19850109   8240   8240   7950
-    9798           8300     12930        4  19850108   8400   8400   8300
-    9799           8410     11810        3  19850107   8400   8500   8390
-    9800           8390      1660        0  19850105   8400   8440   8390
-    9801           8450      1710        0  19850104   8500   8500   8450
-
-        수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가
-    0
-    1
-    2
-    3
-    4
-    ...   ...   ...   ...  ...     ...  ...
-    9797
-    9798
-    9799
-    9800
-    9801
-
-    [9802 rows x 15 columns]
-
-조건검색 조건식 설정 불러오기
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> entrypoint.IsConditionLoaded()
-    False
-    >>> entrypoint.EnsureConditionLoaded()
-    1
-    >>> entrypoint.IsConditionLoaded()
-    True
-
-불러온 조건식 목록 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> condition_name_list = entrypoint.GetConditionNameListAsList()
-    >>> condition_name_list
-    [(0, '대형 저평가 우량주'), (1, '중소형 저평가주')]
-
-조건식 단순 검색
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> condition_name = "대형 저평가 우량주"
-    >>> condition_met_code_list, condition_met_code_list_info = entrypoint.GetCodeListByCondition(condition_name, with_info=True)
-
-    >>> condition_met_code_list
-    ['000240', '001800', '001880', '003230', '003550', '004000', '006040', '006390', '006650', '007700', '009970', '011780', '014830', '020000', '021240', '025540', '030520', '033290', '033780', '036830', '042420', '056190', '057050', '060150', '064960', '069080', '081660', '095660', '096530', '110790', '111770', '137310', '161390', '161890', '185750', '192080', '192400', '200130', '243070', '271560', '284740', '285130', '294870', '300720', '950130']
-
-    >>> condition_met_code_list_info  # same as entrypoint.GetStockQuoteInfoAsDataFrame(condition_met_code_list)
-          종목코드        종목명      현재가     기준가   전일대비 전일대비기호     등락율      거래량    거래대금  \
-    0   000240     한국앤컴퍼니   +13500   13400   +100      2   +0.75    56484     760
-    1   001800     오리온홀딩스   +14600   14250   +350      2   +2.46    69827    1008
-    2   001880       DL건설   -27950   28050   -100      5   -0.36    20925     583
-    3   003230       삼양식품   +91300   90000  +1300      2   +1.44    58660    5289
-    4   003550         LG   +76300   74600  +1700      2   +2.28   249415   18925
-    ..     ...        ...      ...     ...    ...    ...     ...      ...     ...
-    40  284740      쿠쿠홈시스   +36700   35900   +800      2   +2.23    30134    1102
-    41  285130      SK케미칼  +130500  129500  +1000      2   +0.77    58032    7544
-    42  294870  HDC현대산업개발   +15600   14600  +1000      2   +6.85  3145356   49106
-    43  300720      한일시멘트   +19250   18750   +500      2   +2.67   159419    3021
-    44  950130     엑세스바이오   -18400   22400  -4000      5  -17.86  5877689  119649
-
-        체결량  ...    ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가 로
-    0   5549  ...  00000000
-    1     +1  ...  00000000
-    2    369  ...  00000000
-    3     +2  ...  00000000
-    4   +100  ...  00000000
-    ..   ...  ...       ...   ...     ...  ..   ... .. .. .. .. ..
-    40    -3  ...  00000000
-    41    -1  ...  00000000
-    42   -25  ...  00000000
-    43    -4  ...  00000000
-    44   -36  ...  00000000
-
-    [45 rows x 63 columns]
-
-GRPC 스트림 처리 관련 유틸리티 함수 (데모 목적)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> import contextlib
-    >>> import threading
-    >>> import warnings
-
-    >>> import grpc
-
-    >>> @contextlib.contextmanager
-    ... def warn_on_rpc_error_context():
-    ...     try:
-    ...         yield
-    ...     except grpc.RpcError as e:
-    ...         warnings.warn(str(e))
-
-    >>> def warn_on_rpc_error(stream):
-    ...     with warn_on_rpc_error_context():
-    ...         for event in stream:
-    ...             yield event
-
-    >>> def cancel_after(stream, after):
-    ...     timer = threading.Timer(after, stream.cancel)
-    ...     timer.start()
-    ...     return warn_on_rpc_error(stream)
-
-조건식 실시간 검색
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> condition_name = "중소형 저평가주"
-    >>> stream = entrypoint.GetCodeListByConditionAsStream(condition_name)
-
-    >>> condition_met_code_list = []
-    >>> data_list = []
-
-    >>> for event in cancel_after(stream, 10):
-    ...     if event.name == "OnReceiveTrCondition":
-    ...         initially_included_code_list = event.arguments[1].string_value
-    ...         initially_included_code_list = initially_included_code_list.rstrip(';').split(';') if initially_included_code_list else []
-    ...         condition_met_code_list.extend(initially_included_code_list)
-    ...     elif event.name == "OnReceiveRealCondition":
-    ...         code = event.arguments[0].string_value
-    ...         condition_type = event.arguments[1].string_value
-    ...         if condition_type == "I":
-    ...             code_inserted = code
-    ...             condition_met_code_list.append(code_inserted)
-    ...         elif condition_type == "D":
-    ...             code_deleted = code
-    ...             condition_met_code_list.remove(code_deleted)
-    ...     elif event.name == "OnReceiveTrData":
-    ...         columns = event.multi_data.names
-    ...         records = [values.values for values in event.multi_data.values]
-    ...         data = pd.DataFrame.from_records(records, columns=columns)
-    ...         data_list.append(data)
-
-    >>> condition_met_code_list
-    ['900290', '900310', '900340', '002170', '017890', '023600', '036190', '037710', '049430', '073560', '140910', '187870', '192440', '210540', '225220', '263690', '352700', '950190', '900280', '900250']
-
-    >>> data_list
-    []
-
-계좌정보 확인
-~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> account_list = entrypoint.GetAccountList()
-    >>> account_list
-    ['8014526011']
-
-    >>> first_account_no = entrypoint.GetFirstAvailableAccount()
-    >>> first_account_no
-    '8014526011'
-
-주문 요청 (삼성전자 시장가 매수)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> request_name = "삼성전자 1주 시장가 신규 매수"  # 사용자 구분명, 구분가능한 임의의 문자열
-    >>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
-    >>> account_no = "8014526011"  # 계좌번호 10자리, 여기서는 계좌번호 목록에서 첫번째로 발견한 계좌번호로 매수처리
-    >>> order_type = 1  # 주문유형, 1:신규매수
-    >>> code = "005930"  # 종목코드, 앞의 삼성전자 종목코드
-    >>> quantity = 1  # 주문수량, 1주 매수
-    >>> price = 0  # 주문가격, 시장가 매수는 가격 설정 의미 없으므로 기본값 0 으로 설정
-    >>> quote_type = "03"  # 거래구분, 03:시장가
-    >>> original_order_no = ""  # 원주문번호, 주문 정정/취소 등에서 사용
-
-    >>> stream = entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no)
-
-    >>> for event in warn_on_rpc_error(stream):
-    ...     if event.name == "OnReceiveTrData":
-    ...         order_no = event.single_data.values[0]
-    ...     elif event.name == "OnReceiveChejanData":
-    ...         gubun = event.arguments[0].string_value
-    ...         data = dict(zip(event.single_data.names, event.single_data.values))
-    ...         if gubun == "0":
-    ...             status = data["주문상태"]
-    ...             if status == "접수":
-    ...                 pass
-    ...             elif status == "체결":
-    ...                 orders_filled = data["체결량"]
-    ...                 orders_left = data["미체결수량"]
-    ...             elif status == "확인":
-    ...                 org_order_no = data["원주문번호"]
-    ...                 assert original_order_no == org_order_no
-    ...         elif gubun in ["1", "4"]:
-    ...             stocks = data["보유수량"]
-
-키움증권의 실시간 데이터 메타 정보 확인
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> from koapy import KiwoomOpenApiPlusRealType
-
-.. code-block:: python
-
-    >>> realtype_list = KiwoomOpenApiPlusRealType.get_realtype_info_list()
-
-.. code-block:: python
-
-    >>> realtype_descs = [realtype.desc for realtype in realtype_list]
-    >>> realtype_descs
-    ['주식시세', '주식체결', '주식상하한', '주식우선호가', '주식호가잔량', '주식시간외호가', '주식당일거래원', 'ETF NAV', 'ELW 지표', 'ELW 이론가', '주식예상체결', '주식종목정보', '임의연장정보', 'ECN주식시세', 'ECN주식체결', 'ECN주식우선호가', 'ECN주식호가잔량', 'ECN주식시간외호가', 'ECN주식당일거래원', '시간외종목정보', '주식거래원', '주식거래원(1LINE)', '종목별프로그램매매', 'VI정적예상가', 'VI발동/해제-종목별', '종목별프로그램매매2', '종목투자자(잠정)', '종목투자자(거래소)', '대주가능수량', '선물옵션우선호가', '선물시세', '선물호가잔량', '선물이론가', '선물기초자산시세', '실시간상하한가', '옵션시세', '옵션호가잔량', '옵션이론가', '주식옵션시세', '주식옵션호가잔량', '주식옵션이론가', '업종지수', '업종등락', '자체업종지수', '예상업종지수', '시황/뉴스', '환률', '장시작시간', '투자자ticker', '상하한가폭변경', 'VI발동/해제', '투자자별매매', '프로그램매매', '해외시세', '주문체결', '파생잔고', '현물잔고', '예수금', '해외주문체결', '해외잔고', '순간체결량', '주문체결서버상태', '증거금', 'CFD주문', 'CFD체결', 'CFD마진콜경고', 'CFD입출고', '자유포멧', '조건검색', '일반신호', '리얼잔고', '해외리얼잔고', '리얼잔고총합', '해외잔고총합', '스톱로스', '선물옵션합계', '스톱주문', 'CFD주문체결', 'CFD리얼잔고', 'CFD리얼잔고총합', '모니터링 실시간LOG', '주식선물호가잔량', '실시간증거금', 'X-Ray순간체결량', '매입인도체결', '매입인도호가', '코넥스경매매체결', '데이터셋실시간', '홍콩체결', '홍콩시세', '홍콩호가잔량', '홍콩단일가시세', '홍콩업종지수', '홍콩실시간상하한가', '수동자동주문', '자동주문결과', 'TS고저변경', '잔고편입', '기준가변경', '멀티차단', '잔고청산삭제', '후강퉁체결', '후강퉁시세', '후강퉁호가잔량', '후강퉁단일가시세', '후강퉁업종지수', '미체결통보시스템', '채널K실시간티커', '빅데이터종목1분', '빅데이터종목10분', '빅데이터종목1시간', '빅데이터종목당일', '빅데이터뉴스', '신호관리자투자정보', '빅데이터급상승', '빅데이터종목30초', '알-종목포착이탈', '알-매도감시시작', '알-매도감시포착', '알-주문결과', '알-청산시작', '알-청산완료', '알-감시시작', '알-내조건식수정', '알-주문조건수정', '알-제한여부', '알-멀티차단', '알-TS변경', '알-모의주문체결', '알-모의현물잔고', '알-모의 주문체결', '알-모의 리얼잔고', '알-모의리얼잔고총합', '채권체결', '채권호가잔량', '소액채권체결', '소액채권호가잔량', 'CME시세', 'CME미결제약정', 'CME호가잔량', 'EUF시세', 'EUF호가잔량', 'EUREX시세', 'EUREX호가', '배치데이터갱신', '종목마스터갱신', '해외주식주문', '해외주식체결', '해외실시간잔고조회', '미국입출고', '미국종목변경', 'CME/EUREX주문', 'CME/EUREX체결', 'CME배치', 'EUREX배치', 'CME미체결', 'CME실시간잔고', 'CME잔고합', '분할반복주문']
-
-    >>> realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_name("주식시세")
-    >>> realtype_info
-    KiwoomOpenApiPlusRealType('0A', '주식시세', 21, [10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732])
-
-    >>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세")
-    >>> fid_list
-    [10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732]
-
-    >>> KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(10)
-    '현재가'
-
-    >>> fid_names = KiwoomOpenApiPlusRealType.get_field_names_by_realtype_name("주식시세")
-    >>> fid_names
-    ['현재가', '전일대비', '등락율', '매도호가', '매수호가', '누적거래량', '누적거래대금', '시가', '고가', '저가', '전일대비기호', '거래량전일대비', '거래대금증감', '전일거래량대비율', '거래회전율', '거래비용', '시가총액', '822', '567', '568', '732']
-
-실시간 데이터 요청 (삼성전자 주식시세 실시간 데이터 요청)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: python
-
-    >>> code_list = ["005930"]
-    >>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세")
-    >>> opt_type = "0"  # 기존 화면에 추가가 아니라 신규 생성
-
-    >>> stream = entrypoint.GetRealDataForCodesAsStream(
-    ...     code_list,
-    ...     fid_list,
-    ...     opt_type,
-    ...     screen_no=None,  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
-    ...     infer_fids=True,  # True 로 설정 시 주어진 fid_list 를 고집하지 말고 이벤트 처리 함수의 인자로 전달받는 실시간데이터 이름에 따라 유연하게 fid_list 를 추론
-    ...     readable_names=True,  # True 로 설정 시 각 fid 마다 숫자 대신 읽을 수 있는 이름으로 변환하여 반환
-    ...     fast_parse=False,  # True 로 설정 시 이벤트 처리 함수내에서 데이터 값 읽기 시 GetCommRealData() 함수 호출 대신, 이벤트 처리 함수의 인자로 넘어오는 데이터를 직접 활용, infer_fids 가 True 로 설정된 경우만 유의미함
-    ... )
-
-    >>> for event in cancel_after(stream, 10):
-    ...     if event.name == "OnReceiveRealData":
-    ...         data = dict(zip(event.single_data.names, event.single_data.values))
-    ...         if "현재가" in data:
-    ...             current_price = data["현재가"]
-
-사용 종료 후 엔트리포인트 객체 리소스 해제 (연결 해제 및 서버 어플리케이션 종료)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-직접 ``close()`` 메소드 호출:
-
-.. code-block:: python
-
-    >>> entrypoint.close()
-
-혹은 처음부터 컨텍스트 매니저 형태로 리소스 관리:
-
-.. code-block:: python
-
-    >>> with KiwoomOpenApiPlusEntrypoint() as entrypoint:
-    ...     entrypoint.EnsureConnected()
-    ...     ...
-
-
-Installation
-------------
-
-대표적으로 아래와 같이 PyPI_ 를 통해서 설치가 가능합니다:
-
-.. code-block:: console
-
-    $ pip install koapy
-
-만약에 개발 환경을 구축하고자 하는 경우에는 |poetry|_ 를 활용해 구성합니다.
-
-.. code-block:: console
-
-    $ # Install poetry (here using pipx)
-    $ python -m pip install pipx
-    $ python -m pipx ensurepath
-    $ pipx install poetry
-
-    $ # Clone repository
-    $ git clone https://github.com/elbakramer/koapy.git
-    $ cd koapy/
-
-    $ # Install dependencies and hooks
-    $ poetry install
-    $ poetry run pre-commit install
-
-이외에 자세한 설치방법과 관련해서는 Installation_ 문서를 참고하세요.
-
-.. _PyPI: https://pypi.org/project/koapy/
-.. |poetry| replace:: ``poetry``
-.. _poetry: https://python-poetry.org/
-.. _Installation: https://koapy.readthedocs.io/en/latest/installation.html
-
-
-Usage
------
-
-설치 이후 일반적인 사용법에 대해서는 Usage_ 를 참고하세요.
-
-추가적으로 사용법과 관련된 다양한 예시들은 examples_ 폴더 및 notebooks_ipynb_ 폴더에서도 확인 가능합니다.
-혹시나 notebooks_ipynb_ 폴더의 ``.ipynb`` 파일들을 Github 을 통해서 보는데 문제가 있는 경우,
-해당 노트북 주소를 nbviewer_ 에 입력하여 확인해 보세요.
-
-현재 알파 단계이기 때문에 많은 기능들이 실제로 문제없이 동작하는지 충분히 테스트되지 않았습니다.
-만약에 실전 트레이딩에 사용하려는 경우 자체적으로 충분한 테스트를 거친 후 사용하시기 바랍니다.
-
-개발자는 라이브러리 사용으로 인해 발생하는 손실에 대해 어떠한 책임도 지지 않습니다.
-
-또한 알파 단계에서 개발이 진행되면서 라이브러리의 구조가 계속 급격하게 변경될 수 있으니 참고 바랍니다.
-
-.. _Usage: https://koapy.readthedocs.io/en/latest/usage.html
-.. _examples: https://github.com/elbakramer/koapy/tree/master/koapy/examples
-.. _notebooks_ipynb: https://github.com/elbakramer/koapy/tree/master/docs/source/notebooks_ipynb
-.. _nbviewer: https://nbviewer.jupyter.org/
-
-
-Features
---------
-
-KOAPY 는 아래와 같은 방향성을 가지고 개발되었습니다.
-
-GUI 어플리케이션만으로 제한되지 않는 다양한 사용성
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-일반적으로 인터넷 등지에서 접하기 쉬운 관련 예시들을 처음으로 따라가다 보면, 자기도
-모르는 사이에 Qt 기반 어플리케이션을 하나 만들고, 버튼을 하나 추가하고, 이후 모든
-기능들을 죄다 해당 버튼을 클릭 시 작동하는 콜백 함수 하나에 쑤셔 넣고 있는.. 자신을
-발견하게 되더군요.
-
-.. code-block:: python
-
-    # https://wikidocs.net/4240
-
-    import sys
-
-    from PyQt5.QtWidgets import *
-    from PyQt5.QtGui import *
-    from PyQt5.QAxContainer import *
-
-    class MyWindow(QMainWindow):
-        def __init__(self):
-            super().__init__()
-            self.setWindowTitle("PyStock")
-            self.setGeometry(300, 300, 300, 150)
-
-            self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
-
-            btn1 = QPushButton("Login", self)
-            btn1.move(20, 20)
-            btn1.clicked.connect(self.btn1_clicked)
-
-            btn2 = QPushButton("Check state", self)
-            btn2.move(20, 70)
-            btn2.clicked.connect(self.btn2_clicked)
-
-        def btn1_clicked(self):
-            ret = self.kiwoom.dynamicCall("CommConnect()")
-
-        def btn2_clicked(self):
-            if self.kiwoom.dynamicCall("GetConnectState()") == 0:
-                self.statusBar().showMessage("Not connected")
-            else:
-                self.statusBar().showMessage("Connected")
-
-    if __name__ == "__main__":
-        app = QApplication(sys.argv)
-        myWindow = MyWindow()
-        myWindow.show()
-        app.exec_()
-
-사실 기반 라이브러리가 애초에 OCX 형태로서 제공되는 것도 있고, 다른 여러 가지 이유들로
-인해 이처럼 GUI 어플리케이션 형태로 개발을 하는 것이 자연스러운 흐름이고 절대
-잘못되었다고 생각되진 않습니다.
-
-다만 이러한 GUI 환경이 일반적으로 Python 에서 REPL 혹은 Jupyter Notebook 등을 통해서
-인터랙티브하게 결과 값들을 확인해가면서 조금씩 개발해 나가던 것과는 거리가 멀어지면서
-결론적으로 생산성이 떨어지게 되는 건 아닌가 하는 생각이 들었고, 그로 인해 KOAPY 의
-기본적인 인터페이스는 기반이 되는 Qt 환경을 개발자가 직접적으로 고려하진 않으면서도
-기능은 쉽게 사용해 볼 수 있게 끔 하는 게 좋겠다고 생각했습니다.
-
-따라서 KOAPY 의 기본적인 디자인은 우선 외적으로 봤을 때 이게 내부적으로는 Qt 같은
-환경하에서 돌아간다는 것을 바로 알아챌 순 없게 끔 되어 있습니다. 그리고 기본적인
-기능들을 이용하는 데에 있어서도 버튼 클릭 등의 이벤트에 기반한 호출보단 일반적인 함수
-호출과 같은 명령형 프로그래밍이 가능하도록 디자인 하였으며, 문서에서도 해당 사용
-시나리오들을 중점적으로 먼저 소개하고 있습니다.
-
-.. code-block:: python
-
-    from koapy import KiwoomOpenApiPlusEntrypoint
-
-    with KiwoomOpenApiPlusEntrypoint() as entrypoint:
-        entrypoint.EnsureConnected()
-        is_connected = entrypoint.IsConnected()
-        print(is_connected)
-
-
-결론적으로 PyQt5_ 혹은 PySide2_ 를 기반한 GUI 환경에 얽매일 필요 없이 일반적인
-라이브러리처럼 가져다 활용할 수 있으며, 여전히 GUI 기반 어플리케이션 개발이 필요하다면
-내부적으로 사용되는 요소들을 통해 직접 GUI 방향으로 개발을 할 수도 있습니다.
-
-.. code-block:: python
-
-    from koapy.compat.pyside2.QtWidgets import QApplication, QMainWindow
-    from koapy import KiwoomOpenApiPlusQAxWidget
-
-    class MyWindow(QMainWindow):
-        def __init__(self):
-            super().__init__()
-
-            self.kiwoom = KiwoomOpenApiPlusQAxWidget()
-            ...
-
-
-함수 호출등의 과정에서 일반적인 Python 의 관습을 크게 해치지 않는 매끄러운 인터페이스 구성
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Qt 를 통해서 COM/OLE/OCX 객체의 메서드를 호출하려면 |dynamicCall|_ 함수를 활용해야 합니다.
-
-해당 |dynamicCall|_ 함수는 호출하고자 하는 메서드의 프로토타입을 문자열 형태 인자로서
-입력하도록 되어있는데, 단순하게는 매번 메서드를 호출하고자 할 때마다 해당 메서드의
-프로토타입이 어떻게 생겼는지를 문서 등을 참고하고 일일이 적어 넣어줘야 할 수 있습니다.
-
-.. code-block:: python
-
-    control = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
-    control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code)
-
-그 다음으로 보다 나은 방식으로는 이러한 프로토타입을 모든 함수들에 대해서 확인해서
-간단한 래퍼 함수들을 만들어두고 활용하는 게 있겠죠.
-
-.. code-block:: python
-
-    def SetInputValue(name, value):
-        return control.dynamicCall("SetInputValue(const QString&, const QString&)", name, value)
-
-일반적으로는 이런 방식들로도 충분히 사용하는데 무리가 없으리라 생각됩니다만
-개인적으로는 위와 같은 접근 방식에서 몇 가지 우려되는 점들이 신경이 쓰였습니다.
-
-* 프로토타입을 입력하거나 래퍼 함수들을 만들어 넣는 과정에서 발생할 수 있는 휴먼에러
-* 래퍼 함수들을 만들어 놓았더라도 추후 함수의 목록 혹은 특정 함수의 프로토타입에서
-  변경이 발생하는 경우 매번 직접적인 대응이 필요함
-
-따라서 KOAPY 에서는 이러한 지원 함수 목록 및 함수별 프로토타입 정보 확인, 그리고
-이것들을 활용해 특정 메서드를 호출하는 과정까지를 어떻게 프로그래밍적으로 대응할 수
-없을까를 고민했고, 현재는 OpenAPI+ OCX 의 TypeLib 정보를 읽어와 메서드들을 동적으로
-생성하도록 구현해 위에서 우려했던 점들을 해결했습니다.
-
-최종적으론 컨트롤 함수 호출 시 매뉴얼의 명세에 적혀있는 형태 그대로 Python 함수였던
-것처럼 호출이 가능하며, 이후는 KOAPY 가 유연하게 처리합니다. 매번 명세에 맞게
-|dynamicCall|_ 함수의 인자를 적어 넣거나, 모든 존재하는 함수에 대해 미리 래퍼 함수를
-손 아프게 만들어놓을 필요가 없습니다.
-
-.. code-block:: python
-
-    control = KiwoomOpenApiPlusQAxWidget()
-    control.SetInputValue("종목코드", code)
-
-이벤트 처리 및 비동기 프로그래밍 관련 복잡하지 않은 인터페이스 제공
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-비동기 프로그래밍은 일반적으로 어렵습니다. 특히 OpenAPI+ 및 KOAPY 의 경우를 예로
-들어보면 아래와 같은 고민해 볼 만한 부분들이 있습니다.
-
-* 여러 요청에 대한 응답 결과들을 이벤트 타입별 하나씩의 통로로 처리하기 때문에 그들
-  간의 교통정리부터 필요합니다.
-* 콜백 함수 내에서 OpenAPI+ 가 기대하는 혹은 가이드하는 방식에 맞춰서 처리해 주어야
-  하는 특정 단계 혹은 프로세스가 존재하며 이를 적절히 대응해 주어야 합니다.
-* 콜백 함수에서 받은 결과를 최종적으로 해당 결과가 필요한 곳으로 (일반적으론 요청한
-  대상에게로) 잘 전달해 주어야 합니다.
-
-KOAPY 에서는 위의 문제들을 나름의 방식대로 고민하였고 문제들을 해결하여 더 쉽고 나은
-인터페이스를 사용자에게 제공하고 있습니다.
-
-구체적으로 예를 하나 들자면, 일반적인 요청-응답 과정에서 내부적으로 gRPC
-클라이언트-서버 관계를 만들어 요청자가 gRPC 를 통해 특정 요청을 전달하면, 이후 gRPC
-서버에서는 해당 요청에 대한 응답들만 추려서 결과를 요청자측에 스트림 형태로 전달하도록
-디자인되어 있는데요. 여기서 교통정리 및 결과 전달 문제가 자연스럽게 해결되며 부수적으로
-사용자 입장에서는 직접 콜백 함수를 다루기보다는 간접적으로 스트림을
-(``for`` 문을 활용하여) 다룸으로써 더 쉽게 비동기 프로그래밍이 필요한 기능들을 사용할
-수 있는 이점이 있습니다.
-
-PySide2 를 통한 직접적인 방식:
-
-.. code-block:: python
-
-    # 컨트롤 객체
-    control = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
-
-    # 이벤트 시그널
-    on_receive_tr_data_signal = SIGNAL("OnReceiveTrData(const QString&, const QString&, const QString&, const QString&, const QString&, int, const QString&, const QString&, const QString&)")
-
-    # 이벤트 콜백 함수
-    def on_receive_tr_data(screen_no, request_name, tr_code, record_name, prev_next, data_length, error_code, message, splmmsg):
-        handle_event(...)
-
-        # 이벤트 처리 후 필요하다면 등록된 콜백 함수 제거
-        if should_disconnect:
-            control.disconnect(on_receive_tr_data_signal, on_receive_tr_data)
-
-    # 이벤트 시그널에 콜백 함수 연결
-    control.connect(on_receive_tr_data_signal, on_receive_tr_data)
-
-    # TR 입력값 설정
-    control.dynamicCall("SetInputValue(const QString&, const QString&)", ..., ...)
-    ...
-
-    # TR 요청
-    err_code = control.dynamicCall(
-        "CommRqData(const QString&, const QString&, int, const QString&)",
-        request_name,
-        tr_code,
-        prev_next,
-        screen_no,
-    )
-
-KOAPY 방식:
-
-.. code-block:: python
-
-    # TR 요청 후 이벤트가 스트림 형태로 반환
-    for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
-        handle_event(event)
-
-결론적으로는 사용자가 이벤트 처리 및 비동기 프로그래밍에 익숙하지 않더라도 그보다
-비교적 쉬운 인터페이스를 통해 관련 기능들을 활용할 수 있습니다.
-
-더 나아가서는 가장 간단한 로그인 처리부터 TR/실시간 데이터 처리, 그리고 주문처리까지
-다양한 시나리오에 대한 기본 이벤트 처리 로직을 구현해 제공해 사용자들이 비동기
-프로그래밍이 필요한 기능 중 주로 사용되는 기능들에 쉽게 접근할 수 있도록 했습니다.
-
-.. code-block:: python
-
-    stream = entrypoint.LoginCall()
-    stream = entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs)
-    stream = entrypoint.RealCall(screen_no, codes, fids, opt_type)
-    stream = entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no)
-
-여러 일반적인 시나리오들에 대한 다양한 기본 구현체들을 제공
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-KOAPY 에서는 일반적으로 자주 사용되는 기능들에 대해서 사용자들이 쉽게 접근할 수 있도록,
-예를 들어 주식 기본정보 요청부터 일봉/분봉 등 시세 데이터 확인 그리고 예수금/잔고 확인 등등에 대해 미리 구현된 함수를 제공합니다.
-
-.. code-block:: python
-
-    stock_info = entrypoint.GetStockBasicInfoAsDict(stock_code)
-    stock_chart_data = entrypoint.GetDailyStockDataAsDataFrame(stock_code)
-
-    account_deposit = entrypoint.GetDepositInfo(account_no)
-    account_evaluation = (
-        account_evaluation_summary,
-        account_evaluation_per_stock,
-    ) = entrypoint.GetAccountEvaluationStatusAsSeriesAndDataFrame(account_no)
-
-이 중에 함수 호출 결과 중 테이블성 정보들은 |pandas.DataFrame|_ 타입으로 제공해 이후 분석 및 처리가 유용하게끔 했습니다.
-
-.. |pandas.DataFrame| replace:: ``pandas.DataFrame``
-.. _`pandas.DataFrame`: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html
-
-개발과정에서 라이브러리 밖을 드나들 필요가 없도록 자주 확인이 필요한 여러가지 메타 정보들을 함께 제공
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-일반적으로 인터넷 등지에서 접하기 쉬운 관련 대부분 예시들은 사용자가 OpenAPI+ 에 대한
-여러 가지 메타정보들을 이미 다 알고 있다는 걸 가정하고, 아니면 적어도 외부 참고자료를
-확인하는 것을 가정하고 작성되어 있는 경우가 많습니다.
-
-예를 들어 TR 의 입력과 출력 데이터 구조, 실시간 데이터별 FID 목록, 에러코드에 대한
-설명문 등이 이러한 메타정보들에 해당되는데요. 앞서 함수 호출 방식에서의 이슈와 비슷하게,
-이러한 정보들을 매번 참고 자료를 확인하고 그에 맞춰 개발하는 방식에는 어느 정도 한계가
-있습니다.
-
-따라서 KOAPY 에서는 이러한 정보들을 개발하는 과정에서 언어 내 라이브러리에서 바로 조회
-및 활용이 가능하도록 포함시켜 제공합니다. 이로 인해 일차적으로 사용자 입장에서는 매번
-매뉴얼_ 이나 KOAStudio_ 를 열어서 참고하고 이후 일일이 하나씩 하드코딩할 필요가
-없어졌습니다.
-
-.. code-block:: python
-
-    from koapy import KiwoomOpenApiPlusTrInfo
-    tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001")
-
-    from koapy import KiwoomOpenApiPlusRealType
-    realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_name("주식시세")
-
-    from koapy import KiwoomOpenApiPlusError
-    error_message = KiwoomOpenApiPlusError.get_error_message_by_code(-101)
-
-덧붙여서 TR 관련 정보나 실시간 데이터 관련 정보들은 OpenAPI+ 가 설치되어 있는 경우
-해당 경로의 데이터를 참고해 동적으로 생성하도록 되어있는데요. 이로 인해 직접 하드코딩
-등을 했을 때 발생할 수 있는 이슈 없이, 매번 업데이트 시 변경된 내용이 바로바로 적용될
-수 있는 이점 또한 가지고 있습니다.
-
-.. _매뉴얼: https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf
-.. _KOAStudio: https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf#page=7
-
-라이브러리 호환성으로 인해 특정 환경이 강제되는 것을 우회할 수 있도록 시스템 구성
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-키움증권의 OpenAPI+ 는 32bit 환경만 제공하고 있기 때문에 이를 사용하는 쪽도 자연스럽게
-32bit 기반이 되어야 합니다.
-
-여기서는 Python_ 을 32bit 로 사용해야 하는 조건이 붙게 되는 것인데요. 몇몇 외부
-서드파티들에서는 더 이상 32bit 를 지원하지 않는 경우도 많아 다양한 서드파티 기능들과
-접목시키기에는 32bit 제약이 번거로운 점이 많습니다.
-
-KOAPY 에서는 이를 해소하기 위해 gRPC_ 서버-클라이언트 형태의 구성을 잡아 서버에서는
-32bit 기반으로 OpenAPI+ 의 핵심 기능만 제공하도록 하고, 클라이언트에서는 이런 32bit
-제약 없이 결과들을 받아서 이후 여러 서드파티 기능들과 함께 활용할 수 있도록 했습니다.
-
-앞에서는 주로 32bit 제약을 가지고 이야기했지만 더 나아가서는 gRPC_ 의 많은 언어들에
-대한 확장성을 활용하여 Python 이외에 gRPC_ 에서 지원하는 다른 언어들로 클라이언트를
-작성해 사용하는 방식으로도 확장이 가능합니다.
-
-또한 Python_ 에서 Qt_ 를 사용하기 위해서는 PyQt5_ 혹은 PySide2_ 를 사용해야 하는데요.
-KOAPY 에서는 라이선스 등을 고려해서 기본값으로 PySide2_ 를 사용하도록 되어있지만,
-사용자의 필요성에 따라 PySide2_ 대신 PyQt5_ 를 사용하려 할 때 쉽게 변경할 수 있도록
-|qtpy|_ 를 통해서 지원하고 있습니다.
-
-.. _gRPC: https://grpc.io/
-
-.. _Python: https://www.python.org/
-.. _Qt: https://www.qt.io/
-
-.. _PyQt5: https://www.riverbankcomputing.com/software/pyqt/
-.. _PySide2: https://doc.qt.io/qtforpython/index.html
-
-.. |qtpy| replace:: ``qtpy``
-.. _qtpy: https://github.com/spyder-ide/qtpy
-
-키움증권의 OpenAPI+ 기능 자체 이외에 부수적으로 필요할만한 다양한 기능들을 추가로 제공
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-KOAPY 는 키움증권의 OpenAPI+ 핵심 기능 이외에 전체적인 개발 및 활용에 필요한 다양한
-부가기능들을 추가로 제공합니다.
-
-* TR 호출 시 호출 횟수 제한 회피
-* KRX 거래소 휴장일 확인 (|exchange_calendars|_ API 활용)
-* 알람 및 메시지 기능 (|discord.py|_ API 활용)
-
-.. |exchange_calendars| replace:: ``exchange_calendars``
-.. _exchange_calendars: https://github.com/gerrymanoim/exchange_calendars
-.. |discord.py| replace:: ``discord.py``
-.. _`discord.py`: https://discordpy.readthedocs.io/en/stable/
-
-라이브러리 뿐만 아니라 관련 기능들을 추가적인 코드 구현없이 쉽게 사용해볼 수 있도록 (+ 개념 증명 목적으로서) CLI 제공
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-굳이 Python 코드를 작성하지 않더라도 기본적인 기능들을 활용해 볼 수 있도록 여러
-커맨드를 포함하는 CLI 를 제공합니다.
-
-CLI 를 활용하면 마켓별 코드 목록 확인, 주식 기본 정보 확인, 일봉/분봉 데이터 확인 및
-저장, 실시간 데이터 구독 등 다양한 기능들을 코드 구현 없이 사용할 수 있습니다.
-
-.. code-block:: console
-
-    $ koapy get stockcode --market=0
-    $ koapy get stockinfo --code=005930
-    $ koapy get daily --code=005930 --output=005930.xlsx
-    $ koapy watch --code=005930 --realtype="주식시세"
-
-서버도 CLI 커맨드로 쉽게 띄울 수 있습니다.
-
-.. code-block:: console
-
-    $ koapy serve
-
-
-Licensing
----------
-
-KOAPY 는 다중 라이선스 방식으로 배포되며,
-사용자는 자신의 의도 및 사용 방식에 따라 아래 라이선스 옵션들 중 하나를 선택해 사용할 수 있습니다.
-
-* `MIT License`_
-* `Apache License 2.0`_
-* `GNU General Public License v3.0`_ or later
-
-라이선스 선택과 관련하여 추천하는 가이드라인은 아래와 같습니다.
-
-MIT License
-~~~~~~~~~~~
-
-* 일반적인 사용자에게 알맞습니다.
-* 짧고 단순한 라이선스를 선호하시면 해당 라이선스를 선택하세요.
-
-Apache License 2.0
-~~~~~~~~~~~~~~~~~~
-
-* MIT 라이선스와 큰 차이는 없지만, 특허와 관련해서 명시적인 허가조항이 있습니다.
-* 추후 특허권 침해 소송이 우려되는 경우 MIT 라이선스 대신에 선택하시면 됩니다.
-
-GNU General Public License v3.0 or later
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* FSF_/GPL_ 이 추구하는 Copyleft_ 의 가치를 따르신다면 선택 가능한 옵션중 하나입니다.
-* 이외에 backtrader_ 관련 기능들을 활용하시는 경우, KOAPY 는 **반드시** GPLv3+ 로만 배포되어야 합니다.
-* 구체적으로 |koapy.backtrader|_ 모듈 하위의 기능들을 사용한다면 GPLv3+ 배포 조건에 해당됩니다.
-* 이것은 backtrader_ 가 GPLv3+ 로 배포되고 있으며,
-  해당 라이선스의 요구사항에 따라 그것을 사용하는 소프트웨어 또한 GPLv3+ 로 배포되어야 하기 때문입니다.
-
-각 라이선스의 허가 및 요구사항과 관련해서 쉽게 정리된 내용은 `tl;drLegal`_ 에서 참고하실 수 있습니다.
-
-다만 위의 내용이 법률적 조언은 아닌 점 참고 바랍니다.
-
-.. _`MIT License`: https://spdx.org/licenses/MIT.html
-.. _`Apache License 2.0`: http://www.apache.org/licenses/LICENSE-2.0
-.. _`GNU General Public License v3.0`: https://www.gnu.org/licenses/gpl-3.0.html
-
-.. _FSF: https://www.fsf.org/
-.. _GPL: https://www.gnu.org/licenses/licenses.html#GPL
-.. _Copyleft: https://www.gnu.org/licenses/copyleft.html
-
-.. _backtrader: https://github.com/mementum/backtrader
-.. |koapy.backtrader| replace:: ``koapy.backtrader``
-.. _`koapy.backtrader`: https://github.com/elbakramer/koapy/tree/master/koapy/backtrader
-
-.. _`tl;drLegal`: https://tldrlegal.com/
-
-
-Credits
--------
-
-이 패키지는 Cookiecutter_ 와 `elbakramer/cookiecutter-poetry`_ 프로젝트 탬플릿을 사용하여 생성되었습니다.
-
-.. _Cookiecutter: https://github.com/audreyr/cookiecutter
-.. _`elbakramer/cookiecutter-poetry`: https://github.com/elbakramer/cookiecutter-poetry
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 7ba16ae6..00000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Security Policy
-
-## Supported Versions
-
-While this project is currently in alpha,
-no major security update supports are guaranteed.
-
-| Version | Supported          |
-| ------- | ------------------ |
-| < 1.0   | :x:                |
-
-## Reporting a Vulnerability
-
-Go to Issues and create a new issue about the vulnerability to report.
-Add `security` tag to the issue while creating the issue.
diff --git a/_modules/index.html b/_modules/index.html
new file mode 100644
index 00000000..ecc8fff3
--- /dev/null
+++ b/_modules/index.html
@@ -0,0 +1,315 @@
+
+
+
+
+  
+    
+    
+    Overview: module code — KOAPY 0.8.3 documentation
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+
+  
+  
+ + +
+
+ + +
+ +

All modules for which code is available

+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.html b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.html new file mode 100644 index 00000000..8e8bbe6b --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.html @@ -0,0 +1,268 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint

+import threading
+
+import pywintypes
+import win32com.client
+
+from requests.structures import CaseInsensitiveDict
+
+from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin import (
+    CybosPlusEntrypointMixin,
+)
+from koapy.backend.daishin_cybos_plus.core.CybosPlusError import CybosPlusRequestError
+from koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter import (
+    CybosPlusLookupRequestRateLimiter,
+    CybosPlusTradeRequestRateLimiter,
+)
+from koapy.utils.platform import is_32bit
+
+
+
[docs]class CybosPlusDispatch: + def __init__(self, entrypoint, progid): + self._entrypoint = entrypoint + self._progid = progid + self._is_trade_related = progid.startswith("CpTrade.") + + self._dispatch = win32com.client.gencache.EnsureDispatch(progid) + + if self._is_trade_related: + self._rate_limiter = self._entrypoint._trade_rate_limiter + else: + self._rate_limiter = self._entrypoint._lookup_rate_limiter + + self._error_checking_request_methods = {} + self._rate_limited_request_methods = {} + + for name in ["BlockRequest", "BlockRequest2", "Request"]: + if hasattr(self._dispatch, name): + method = getattr(self._dispatch, name) + if callable(method): + method = CybosPlusRequestError.wrap_to_check_code_or_raise(method) + self._error_checking_request_methods[ + "ErrorChecking" + name + ] = method + method = self._rate_limiter(method) + self._rate_limited_request_methods["RateLimited" + name] = method + + def __getattr__(self, name): + if hasattr(self._dispatch, name): + return getattr(self._dispatch, name) + elif name in self._rate_limited_request_methods: + return self._rate_limited_request_methods[name] + elif name in self._error_checking_request_methods: + return self._error_checking_request_methods[name] + else: + raise AttributeError( + "'{}' object has no attribute '{}'".format(type(self), name) + ) + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._entrypoint, self._progid + )
+ + +
[docs]class CybosPlusIncompleteProgID: + def __init__(self, entrypoint, prefix): + self._entrypoint = entrypoint + self._prefix = prefix + + self._cache = {} + self._lock = threading.RLock() + + def __getattr__(self, name): + if name not in self._cache: + with self._lock: + if name not in self._cache: + progid = "{}.{}".format(self._prefix, name) + try: + dispatch = CybosPlusDispatch(self._entrypoint, progid) + except pywintypes.com_error as e: # pylint: disable=no-member + raise AttributeError( + "'{}' object has no attribute '{}'".format(type(self), name) + ) from e + self._cache[name] = dispatch + return self._cache[name] + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._entrypoint, self._prefix + )
+ + +
[docs]class CybosPlusEntrypoint(CybosPlusEntrypointMixin): + + """ + http://cybosplus.github.io/ + """ + + def __init__(self): + assert is_32bit(), "Control object should be created in 32bit environment" + + self._attribute_mapping = { + "CpDib": "DsCbo1", + "CpSysDib": "CpSysDib", + "CpTrade": "CpTrade", + "CpUtil": "CpUtil", + "DsCbo1": "DsCbo1", + } + self._attribute_mapping = CaseInsensitiveDict(self._attribute_mapping) + + self._cache = {} + self._lock = threading.RLock() + + self._lookup_rate_limiter = CybosPlusLookupRequestRateLimiter() + self._trade_rate_limiter = CybosPlusTradeRequestRateLimiter() + + def __getattr__(self, name): + if name not in self._attribute_mapping: + raise AttributeError( + "'{}' object has no attribute '{}'".format(type(self), name) + ) + name = self._attribute_mapping[name] + if name not in self._cache: + with self._lock: + if name not in self._cache: + self._cache[name] = CybosPlusIncompleteProgID(self, name) + return self._cache[name]
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.html b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.html new file mode 100644 index 00000000..f58f74ba --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.html @@ -0,0 +1,700 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin

+import datetime
+import json
+import logging
+import math
+import subprocess
+
+import pandas as pd
+import pytz
+
+from exchange_calendars import get_calendar
+
+from koapy.utils.ctypes import is_admin
+from koapy.utils.exchange_calendars import get_last_session_date
+from koapy.utils.itertools import chunk
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.subprocess import function_to_subprocess_args
+
+
+
[docs]class CybosPlusEntrypointMixin(Logging): +
[docs] def GetConnectState(self): + return self.CpUtil.CpCybos.IsConnect
+ + @classmethod +
[docs] def ConnectUsingPywinauto_Impl(cls, credentials=None): + """ + https://github.com/ippoeyeslhw/cppy/blob/master/cp_luncher.py + """ + + import pywinauto + + is_in_development = False + + if credentials is None: + from koapy.config import config + + credentials = config.get("koapy.backend.daishin_cybos_plus.credentials") + + userid = credentials.get("user_id") + password = credentials.get("user_password") + cert = credentials.get("cert_password") + + auto_account_password = credentials.get("auto_account_password") + auto_cert_password = credentials.get("auto_cert_password") + price_check_only = credentials.get("price_check_only") + + account_passwords = credentials.get("account_passwords") + + cls.logger.info("Starting CYBOS Starter application") + _app = pywinauto.Application().start( + r"C:\DAISHIN\STARTER\ncStarter.exe /prj:cp" + ) # pylint: disable=unused-variable + desktop = pywinauto.Desktop(allow_magic_lookup=False) + + try: + cls.logger.info( + "Waiting for possible popup which asks for shutting down existing program" + ) + ask_stop = desktop.window(title="ncStarter") + ask_stop.wait("ready", timeout=10) + except pywinauto.timings.TimeoutError: + cls.logger.info("No existing program found to be shutdown") + else: + cls.logger.info("Existing program found, shutting down") + if is_in_development: + ask_stop.print_control_identifiers() + if ask_stop["Static2"].window_text().endswith("종료하시겠습니까?"): + ask_stop["Button1"].click() + try: + cls.logger.info("Wating for possible failure message on shutdown") + ask_stop = desktop.window(title="ncStarter") + ask_stop.wait("ready", timeout=10) + except pywinauto.timings.TimeoutError: + cls.logger.info("Successfully shutdown existing program") + else: + cls.logger.error("Failed to shutdown existing program") + if is_in_development: + ask_stop.print_control_identifiers() + if ask_stop["Static2"].window_text().endswith("종료할 수 없습니다."): + ask_stop["Button"].click() + raise RuntimeError("Cannot stop existing program") + + try: + cls.logger.info("Waiting for CYBOS Starter login screen") + starter = desktop.window(title="CYBOS Starter") + starter.wait("ready", timeout=30) + except pywinauto.timings.TimeoutError: + cls.logger.exception("Failed to find login screen") + raise + + if is_in_development: + starter.print_control_identifiers() + + if userid: + cls.logger.info("Putting user id") + starter["Edit1"].set_text(userid) + if password: + cls.logger.info("Putting user password") + starter["Edit2"].set_text(password) + else: + raise RuntimeError("No user password given") + + if not price_check_only: + if cert: + cls.logger.info("Putting cert password") + starter["Edit3"].set_text(cert) + else: + raise RuntimeError("No cert password given") + + if price_check_only: + if starter["Edit3"].is_enabled(): + cls.logger.info("Checking price check only option") + starter["Button6"].check_by_click() + else: + if not starter["Edit3"].is_enabled(): + starter["Button6"].uncheck_by_click() + + if auto_account_password: + cls.logger.info("Checking auto account password option") + starter["Button4"].check() # check dosen't work + try: + confirm = desktop.window(title="대신증권") + confirm.wait("ready", timeout=5) + except pywinauto.timings.TimeoutError: + pass + else: + if is_in_development: + confirm.print_control_identifiers() + confirm["Button"].click() + else: + starter["Button4"].uncheck() # uncheck dosen't work + + if auto_cert_password: + cls.logger.info("Checking auto cert password option") + starter["Button5"].check() # check dosen't work + try: + confirm = desktop.window(title="대신증권") + confirm.wait("ready", timeout=5) + except pywinauto.timings.TimeoutError: + pass + else: + if is_in_development: + confirm.print_control_identifiers() + confirm["Button"].click() + else: + starter["Button5"].uncheck() # uncheck dosen't work + + cls.logger.info("Clicking login button") + starter["Button1"].click() + + cls.logger.info("Setting account passwords if necessary") + should_stop = False + while not should_stop: + try: + cls.logger.info("Waiting for account password setting screen") + account_password = desktop.window(title="종합계좌 비밀번호 확인 입력") + account_password.wait("ready", timeout=5) + except pywinauto.timings.TimeoutError: + cls.logger.info("Account password setting screen not found") + should_stop = True + else: + cls.logger.info("Account password setting screen found") + if is_in_development: + account_password.print_control_identifiers() + account_no = ( + account_password["Static"].window_text().split(":")[-1].strip() + ) + if account_no in account_passwords: + account_password["Edit"].set_text(account_passwords[account_no]) + else: + raise RuntimeError( + "No account password given for account %s" % account_no + ) + account_password["Button1"].click() + + try: + cls.logger.info("Waiting for starter screen to be closed") + starter.wait_not("visible", timeout=60) + except pywinauto.timings.TimeoutError: + cls.logger.warning("Could not wait for starter screen to be closed") + else: + cls.logger.info("Starter screen is closed") + try: + cls.logger.info("Waiting for notice window") + notice = desktop.window(title="공지사항") + notice.wait("ready", timeout=60) + except pywinauto.timings.TimeoutError: + cls.logger.info("No notice window found") + else: + cls.logger.info("Closing notice window") + notice.close() + try: + cls.logger.info("Waiting for the notice window to be closed") + notice.wait_not("visible", timeout=60) + except pywinauto.timings.TimeoutError: + cls.logger.warning("Could not wait for notice screen to be closed") + else: + cls.logger.info("Notice window is closed")
+ + @classmethod +
[docs] def ConnectUsingPywinauto_RunScriptInSubprocess(cls, credentials=None): + def main(): + # pylint: disable=redefined-outer-name,reimported,import-self + import json + import sys + + from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint import ( + CybosPlusEntrypoint, + ) + + credentials = json.load(sys.stdin) + CybosPlusEntrypoint.ConnectUsingPywinauto_Impl(credentials) + + args = function_to_subprocess_args(main) + return subprocess.run( + args, input=json.dumps(credentials), text=True, check=True + )
+ +
[docs] def ConnectUsingPywinauto(self, credentials=None): + return self.ConnectUsingPywinauto_RunScriptInSubprocess(credentials)
+ +
[docs] def Connect(self, credentials=None): + assert is_admin(), "Connect() method requires to be run as administrator" + + self.ConnectUsingPywinauto(credentials) + + if self.GetConnectState() == 0: + self.logger.error("Failed to start and connect to CYBOS Plus") + else: + self.logger.info("Succesfully connected to CYBOS Plus") + + return self.GetConnectState()
+ +
[docs] def CommConnect(self, credentials=None): + return self.Connect(credentials)
+ +
[docs] def EnsureConnected(self, credentials=None): + errcode = 0 + if self.GetConnectState() == 0: + self.Connect(credentials) + if self.GetConnectState() == 0: + raise RuntimeError("CYBOS Plus is not running, please start CYBOS Plus") + return errcode
+ +
[docs] def GetCodeListByMarketAsList(self, market): + """ + 0: 구분없음 + 1: 거래소 + 2: 코스닥 + 3: 프리보드 + 4: KRX + """ + codes = self.CpUtil.CpCodeMgr.GetStockListByMarket(market) + codes = list(codes) + return codes
+ +
[docs] def GetKospiCodeList(self): + codes = self.GetCodeListByMarketAsList(1) + return codes
+ +
[docs] def GetKosdaqCodeList(self): + codes = self.GetCodeListByMarketAsList(2) + return codes
+ +
[docs] def GetGeneralCodeList( + self, + include_preferred_stock=False, + include_etn=False, + include_etf=False, + include_mutual_fund=False, + include_reits=False, + include_kosdaq=False, + ): + + codes = self.GetCodeListByMarketAsList(1) + codemgr = self.CpUtil.CpCodeMgr + + if not include_preferred_stock: + codes = [code for code in codes if code.endswith("0")] + if not include_etn: + codes = [code for code in codes if not code.startswith("Q")] + if not include_etf: + codes = [ + code + for code in codes + if codemgr.GetStockSectionKind(code) not in [10, 12] + ] + if not include_mutual_fund: + codes = [ + code for code in codes if codemgr.GetStockSectionKind(code) not in [2] + ] + if not include_reits: + codes = [ + code for code in codes if codemgr.GetStockSectionKind(code) not in [3] + ] + + if include_kosdaq: + codes += self.GetCodeListByMarketAsList(2) + + codes = sorted(codes) + + return codes
+ +
[docs] def GetStockDataAsDataFrame( + self, + code, + chart_type, + interval, + start_date=None, + end_date=None, + adjusted_price=False, + adjustement_only=False, + ): + """ + http://cybosplus.github.io/cpsysdib_rtf_1_/stockchart.htm + """ + chart = self.CpSysDib.StockChart + + calendar = get_calendar("XKRX") + tz = calendar.tz or pytz.timezone("Asia/Seoul") + + needs_time = chart_type in ["m", "T"] + + if len(code) == 6 and not code.startswith("A"): + code = "A" + code + + fids = [0] + + if needs_time: + fids += [1] + + if not adjustement_only: + fids += [2, 3, 4, 5, 8, 9] + else: + assert chart_type == "D" + adjusted_price = True + + if adjusted_price and chart_type == "D": + fids += [18, 19] + + num_fids = len(fids) + sorted_fids = sorted(fids) + field_indexes = [sorted_fids.index(i) for i in fids] + + maximum_value_count = 20000 + expected_count = math.floor(maximum_value_count / num_fids) - 1 + request_count = expected_count + 1 + + date_format_arg = "%Y%m%d%H%M%S" + date_format_input = "%Y%m%d" + + if start_date is None: + start_date = get_last_session_date().astimezone(tz).to_pydatetime() + if isinstance(start_date, str): + start_date_len = len(start_date) + if start_date_len == 14: + start_date = datetime.datetime.strptime(start_date, date_format_arg) + elif start_date_len == 8: + start_date = datetime.datetime.strptime(start_date, date_format_input) + else: + raise ValueError + if not isinstance(start_date, datetime.datetime): + raise ValueError + + start_date = start_date.astimezone(tz) + + internal_start_date = start_date + + if end_date is not None: + if isinstance(end_date, str): + end_date_len = len(end_date) + if end_date_len == 14: + end_date = datetime.datetime.strptime(end_date, date_format_arg) + elif end_date_len == 8: + end_date = datetime.datetime.strptime(end_date, date_format_input) + else: + raise ValueError + if not isinstance(end_date, datetime.datetime): + raise ValueError + + end_date = end_date.astimezone(tz) + + should_stop = False + dataframes = [] + + while not should_stop: + chart.SetInputValue(0, code) + chart.SetInputValue(1, ord("2")) + chart.SetInputValue(2, int(internal_start_date.strftime(date_format_input))) + chart.SetInputValue(4, request_count) + chart.SetInputValue(5, fids) + chart.SetInputValue(6, ord(chart_type)) + chart.SetInputValue(7, int(interval)) + chart.SetInputValue( + 9, ord("1") if adjusted_price else ord("0") + ) # 기본으로 수정주가 적용하지 않음 + + self.logger.debug("Requesting from %s", internal_start_date) + chart.RateLimitedBlockRequest() + + received_count = chart.GetHeaderValue(3) + self.logger.debug( + "Requested %d, received %d records", request_count, received_count + ) + + num_fields = chart.GetHeaderValue(1) + assert num_fields == num_fids + + names = chart.GetHeaderValue(2) + names = [names[i] for i in field_indexes] + + records = [] + for i in range(received_count): + record = [chart.GetDataValue(j, i) for j in field_indexes] + records.append(record) + + df = pd.DataFrame.from_records(records, columns=names) + + last_date = datetime.datetime.strptime( + df.iloc[-1]["날짜"].astype(int).astype(str), date_format_input + ) + last_date = last_date.astimezone(tz) + + if df.shape[0] > 0 and self.logger.isEnabledFor(logging.DEBUG): + from_date = datetime.datetime.strptime( + df.iloc[0]["날짜"].astype(int).astype(str), date_format_input + ) + from_date = from_date.astimezone(tz) + self.logger.debug( + "Received data from %s to %s for code %s", + from_date, + last_date, + code, + ) + + should_stop = received_count < expected_count + + if not should_stop and end_date is not None: + should_stop = last_date <= end_date + + if not should_stop: + self.logger.debug("More data to request remains") + internal_start_date = last_date + nrows_before_truncate = df.shape[0] + datetimes = pd.to_datetime( + df["날짜"].astype(int).astype(str), format="%Y%m%d" + ) + datetimes = datetimes.dt.tz_localize(tz) + condition = datetimes > last_date + df = df.loc[condition] + nrows_after_truncate = df.shape[0] + self.logger.debug( + "Trailing rows truncated: %d", + nrows_before_truncate - nrows_after_truncate, + ) + else: + self.logger.debug("No more data to request") + if end_date is not None: + nrows_before_truncate = df.shape[0] + dates = df["날짜"].astype(int).astype(str) + if needs_time: + times = df["시간"].astype(int).astype(str).str.ljust(6, "0") + datetimes = dates.str.cat(times) + datetimes = pd.to_datetime(datetimes, format="%Y%m%d%H%M%S") + else: + datetimes = dates + datetimes = pd.to_datetime(datetimes, format="%Y%m%d") + datetimes = datetimes.dt.tz_localize(tz) + condition = datetimes > end_date + df = df.loc[condition] + nrows_after_truncate = df.shape[0] + self.logger.debug( + "Trailing rows truncated: %d", + nrows_before_truncate - nrows_after_truncate, + ) + + dataframes.append(df) + + df = pd.concat(dataframes) + df.reset_index(drop=True, inplace=True) + + return df
+ +
[docs] def GetDailyStockDataAsDataFrame( + self, code, start_date=None, end_date=None, adjusted_price=False + ): + return self.GetStockDataAsDataFrame( + code, "D", 1, start_date, end_date, adjusted_price=adjusted_price + )
+ +
[docs] def GetMinuteStockDataAsDataFrame( + self, code, interval, start_date=None, end_date=None, adjusted_price=False + ): + return self.GetStockDataAsDataFrame( + code, "m", interval, start_date, end_date, adjusted_price=adjusted_price + )
+ +
[docs] def GetDailyAdjustmentRatioAsDataFrame(self, code, start_date=None, end_date=None): + return self.GetStockDataAsDataFrame( + code, "D", 1, start_date, end_date, adjustement_only=True + )
+ +
[docs] def GetCurrentStockDataAsDataFrame(self, codes): + """ + http://cybosplus.github.io/cpdib_rtf_1_/stockmst2.htm + """ + stock = self.DsCbo1.StockMst2 + + names = [ + "종목코드", + "종목명", + "시간", + "현재가", + "전일대비", + "상태구분", + "시가", + "고가", + "저가", + "매도호가", + "매수호가", + "거래량", + "거래대금", + "총매도잔량", + "총매수잔량", + "매도잔량", + "매수잔량", + "상장주식수", + "외국인보유비율", + "전일종가", + "전일거래량", + "체결강도", + "순간체결량", + "체결가비교", + "호가비교", + "동시호가구분", + "예상체결가", + "예상체결가 전일대비", + "예상체결가 상태구분", + "예상체결가 거래량", + ] + fids = list(range(len(names))) + + dataframes = [] + for code_chunk in chunk(codes, 110): + stock.SetInputValue(0, ",".join(code_chunk)) + stock.RateLimitedBlockRequest() + received_count = stock.GetHeaderValue(0) + records = [] + for i in range(received_count): + record = [stock.GetDataValue(j, i) for j in fids] + records.append(record) + + df = pd.DataFrame.from_records(records, columns=names) + dataframes.append(df) + + df = pd.concat(dataframes) + df.reset_index(drop=True, inplace=True) + + return df
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusError.html b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusError.html new file mode 100644 index 00000000..07609002 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusError.html @@ -0,0 +1,216 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.core.CybosPlusError

+from functools import wraps
+
+
+
[docs]class CybosPlusError(Exception): + + pass
+ + +
[docs]class CybosPlusRequestError(CybosPlusError): + + """ + 아래 문서에서 [BlockRequest/Blockrequest2/Request의 리턴값] 내용 참조 + http://cybosplus.github.io/cputil_rtf_1_/cybosplus_interface.htm + """ + +
[docs] ERROR_MESSAGE_BY_CODE = { + 0: "정상요청", + 1: "통신요청 실패", + 2: "주문확인창에서 취소", + 3: "그외의 내부 오류", + 4: "주문요청 제한 개수 초과", + }
+ + @classmethod +
[docs] def get_error_message_by_code(cls, code, default=None): + return cls.ERROR_MESSAGE_BY_CODE.get(code, default)
+ + @classmethod +
[docs] def check_code_or_raise(cls, code): + if code != 0: + raise cls(code) + return code
+ + @classmethod +
[docs] def wrap_to_check_code_or_raise(cls, func): + @wraps(func) + def wrapper(*args, **kwargs): + return cls.check_code_or_raise(func(*args, **kwargs)) + + return wrapper
+ + @classmethod +
[docs] def try_or_raise(cls, arg): + if isinstance(arg, int): + return cls.check_code_or_raise(arg) + elif callable(arg): + return cls.wrap_to_check_code_or_raise(arg) + else: + raise TypeError("Expected 'int' or 'callable' but %s found" % type(arg))
+ + def __init__(self, code, message=None): + if message is None: + message = self.get_error_message_by_code(code) + + super().__init__(message) + + self._code = code + self._message = message + + def __str__(self): + return self._message + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._code, self._message + ) + + @property +
[docs] def code(self): + return self._code
+ + @property +
[docs] def message(self): + return self._message
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter.html b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter.html new file mode 100644 index 00000000..af79da39 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter.html @@ -0,0 +1,169 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter

+from koapy.utils.rate_limiting.RateLimiter import TimeWindowRateLimiter
+
+
+
[docs]class CybosPlusLookupRequestRateLimiter(TimeWindowRateLimiter): + + """ + 시세 오브젝트 조회 제한: 15초에 최대 60건으로제한 + + Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. + http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640 + """ + + def __init__(self): + super().__init__(15, 60)
+ + +
[docs]class CybosPlusTradeRequestRateLimiter(TimeWindowRateLimiter): + + """ + 주문관련 오브젝트 조회 제한: 15초에 최대 20건으로제한 + + Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. + http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640 + """ + + def __init__(self): + super().__init__(15, 20)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.html new file mode 100644 index 00000000..ca044a81 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.html @@ -0,0 +1,302 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy

+import threading
+
+import grpc
+
+from requests.structures import CaseInsensitiveDict
+
+from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin import (
+    CybosPlusEntrypointMixin,
+)
+from koapy.backend.daishin_cybos_plus.proxy import (
+    CybosPlusProxyService_pb2,
+    CybosPlusProxyService_pb2_grpc,
+)
+from koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils import (
+    AssignPrimitive,
+    ExtractPrimitive,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class CybosPlusDispatchProxyMethod: + def __init__(self, proxy, name): + self._proxy = proxy + self._name = name + + def __call__(self, *args, **kwargs): + return self._proxy._InvokeMethod(self._name, args)
+ + +
[docs]class CybosPlusDispatchProxy(Logging): + def __init__(self, proxy, progid): + self._proxy = proxy + self._progid = progid + + self._is_trade_related = self._progid.startswith("CpTrade.") + + request = CybosPlusProxyService_pb2.DispatchRequest() + request.prog = self._progid + + self._dispatch = self._proxy._stub.Dispatch(request) + + def _GetProperty(self, name): + request = CybosPlusProxyService_pb2.PropertyRequest() + request.prog = self._progid + request.name = name + should_stop = False + while not should_stop: + # pylint: disable=protected-access + response_future = self._proxy._stub.Property.future( + request, timeout=self._proxy._timeout + ) + try: + response = response_future.result() + except grpc.RpcError: + if response_future.code() == grpc.StatusCode.DEADLINE_EXCEEDED: + self.logger.warning("Property %s lookup failed, retrying...", name) + else: + raise + else: + should_stop = True + result = ExtractPrimitive(response.value) + return result + + def _InvokeMethod(self, name, args): + request = CybosPlusProxyService_pb2.MethodRequest() + request.prog = self._progid + request.name = name + for arg in args: + AssignPrimitive(request.arguments.add().value, arg) + should_stop = False + while not should_stop: + # pylint: disable=protected-access + response_future = self._proxy._stub.Method.future( + request, timeout=self._proxy._timeout + ) + try: + response = response_future.result() + except grpc.RpcError: + if response_future.code() == grpc.StatusCode.DEADLINE_EXCEEDED: + self.logger.warning( + "Method invocation %s(%s) timed out, retrying...", + name, + ", ".join(map(repr, args)), + ) + else: + raise + else: + should_stop = True + result = ExtractPrimitive(response.return_value) + return result + + def __getattr__(self, name): + if name in self._dispatch.properties: + return self._GetProperty(name) + elif name in self._dispatch.methods: + return CybosPlusDispatchProxyMethod(self, name) + else: + raise AttributeError
+ + +
[docs]class CybosPlusIncompleteProgIDProxy: + def __init__(self, proxy, prefix): + self._proxy = proxy + self._prefix = prefix + + self._cache = {} + self._lock = threading.RLock() + + def __getattr__(self, name): + if name not in self._cache: + with self._lock: + if name not in self._cache: + progid = "{}.{}".format(self._prefix, name) + self._cache[name] = CybosPlusDispatchProxy(self._proxy, progid) + return self._cache[name]
+ + +
[docs]class CybosPlusEntrypointProxy(CybosPlusEntrypointMixin): + def __init__(self, host=None, port=None): + if host is None: + host = "localhost" + if port is None: + port = 3031 + + self._host = host + self._port = port + + self._address = self._host + ":" + str(self._port) + self._channel = grpc.insecure_channel(self._address) + self._stub = CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceStub( + self._channel + ) + + self._timeout = 10 + + grpc.channel_ready_future(self._channel).result(timeout=5) + + self._attribute_mapping = { + "CpDib": "DsCbo1", + "CpSysDib": "CpSysDib", + "CpTrade": "CpTrade", + "CpUtil": "CpUtil", + "DsCbo1": "DsCbo1", + } + self._attribute_mapping = CaseInsensitiveDict(self._attribute_mapping) + + self._cache = {} + self._lock = threading.RLock() + + def __getattr__(self, name): + if name not in self._attribute_mapping: + raise AttributeError( + "'{}' object has no attribute '{}'".format(type(self), name) + ) + name = self._attribute_mapping[name] + if name not in self._cache: + with self._lock: + if name not in self._cache: + self._cache[name] = CybosPlusIncompleteProgIDProxy(self, name) + return self._cache[name]
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService.html new file mode 100644 index 00000000..95901cb1 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService.html @@ -0,0 +1,188 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService

+from concurrent.futures import ThreadPoolExecutor
+
+import grpc
+
+from koapy.backend.daishin_cybos_plus.proxy import CybosPlusProxyService_pb2_grpc
+from koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer import (
+    CybosPlusProxyServiceServicer,
+)
+
+
+
[docs]class CybosPlusProxyService: + def __init__(self, host=None, port=None, max_workers=None): + if host is None: + host = "localhost" + if port is None: + port = 3031 + + if max_workers is None: + max_workers = None + + self._host = host + self._port = port + self._max_workers = max_workers + + self._address = self._host + ":" + str(self._port) + self._servicer = CybosPlusProxyServiceServicer() + self._executor = ThreadPoolExecutor(max_workers=self._max_workers) + + self._server = grpc.server(self._executor) + CybosPlusProxyService_pb2_grpc.add_CybosPlusProxyServiceServicer_to_server( + self._servicer, self._server + ) + self._server.add_insecure_port(self._address) + + def __getattr__(self, name): + return getattr(self._server, name)
+ + +
[docs]def main(): + service = CybosPlusProxyService() + service.start() + service.wait_for_termination()
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils.html new file mode 100644 index 00000000..18702d2a --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils.html @@ -0,0 +1,205 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils

+import os
+import subprocess
+
+
+
[docs]def AssignPrimitive(message, value): + if value is None: + pass + elif isinstance(value, str): + message.string_value = value + elif isinstance(value, int): + message.long_value = value + elif isinstance(value, bool): + message.bool_value = value + elif isinstance(value, float): + message.float_value = value + elif isinstance(value, list): + for item in value: + AssignPrimitive(message.list_value.values.add(), item) + elif isinstance(value, tuple): + for item in value: + AssignPrimitive(message.tuple_value.values.add(), item) + else: + raise TypeError + return message
+ + +
[docs]def ExtractPrimitive(message): + if message.HasField("string_value"): + return message.string_value + elif message.HasField("long_value"): + return message.long_value + elif message.HasField("bool_value"): + return message.bool_value + elif message.HasField("float_value"): + return message.float_value + elif message.HasField("list_value"): + return list(ExtractPrimitive(value) for value in message.list_value.values) + elif message.HasField("tuple_value"): + return tuple(ExtractPrimitive(value) for value in message.tuple_value.values)
+ + +
[docs]def Protoc(): + proto_filename = "CybosPlusProxyService.proto" + proto_filedir = os.path.dirname(os.path.realpath(__file__)) + project_dir = os.path.realpath(os.path.join(proto_filedir, "../../..")) + proto_path = project_dir + python_out = project_dir + grpc_python_out = python_out + proto_filepath = os.path.join(proto_filedir, proto_filename) + cmd = [ + "python", + "-m", + "grpc_tools.protoc", + "--proto_path=%s" % proto_path, + "--python_out=%s" % python_out, + "--grpc_python_out=%s" % grpc_python_out, + proto_filepath, + ] + _ = subprocess.run(cmd, cwd=project_dir, check=True)
+ + +if __name__ == "__main__": + Protoc() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer.html new file mode 100644 index 00000000..e368faf6 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer.html @@ -0,0 +1,307 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer

+import queue
+import threading
+
+import pythoncom
+import win32com.client
+
+from koapy.backend.daishin_cybos_plus.proxy import (
+    CybosPlusProxyService_pb2,
+    CybosPlusProxyService_pb2_grpc,
+)
+from koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils import (
+    AssignPrimitive,
+    ExtractPrimitive,
+)
+
+
+
[docs]class CybosPlusEvent: + def __init__(self, iterator): + self._iterator = iterator + self._done = threading.Event() + + def __del__(self): + self.done() + +
[docs] def done(self): + self._done.set() + self._iterator._events.task_done() # pylint: disable=protected-access
+ +
[docs] def wait_for_done(self): + self._done.wait()
+ + +
[docs]class CybosPlusEventIterator: + def __init__(self, handler): + self._handler = handler + self._events = queue.Queue() + self._sentinel = object() + self._invalid = False + with self._handler._lock: + self._handler._iterators.append(self) + + def __del__(self): + self._invalid = True + self._events.put(self._sentinel) + with self._handler._lock: + if self in self._handler._iterators: + self._handler._iterators.remove(self) + +
[docs] def notify(self): + if not self._invalid: + event = CybosPlusEvent(self) + self._events.put(event) + return event + else: + raise ValueError
+ + def __next__(self): + if self._invalid: + raise StopIteration + event = self._events.get() + if event is self._sentinel: + raise StopIteration + return event
+ + +
[docs]class CybosPlusEventHandler: + def __init__(self): + self._lock = threading.RLock() + self._iterators = [] + +
[docs] def OnRecieved(self): + with self._lock: + events = [iterator.notify() for iterator in self._iterators] + for event in events: + event.wait_for_done()
+ + def __iter__(self): + return CybosPlusEventIterator(self)
+ + +
[docs]class CybosPlusProxyServiceServicer( + CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer +): + + _lock = threading.RLock() + + _dispatches = {} + _handlers = {} + + def _EnsureDispatch(self, prog): + if prog not in self._dispatches: + with self._lock: + if prog not in self._dispatches: + pythoncom.CoInitialize() # pylint: disable=no-member + dispatch = win32com.client.gencache.EnsureDispatch(prog) + self._dispatches[prog] = dispatch + if False: # TODO: 이벤트 처리 관련해서 아직 개발하지 못함 + handler = win32com.client.WithEvents( + dispatch, CybosPlusEventHandler + ) + self._handlers[prog] = handler + dispatch = self._dispatches[prog] + return dispatch + + def _GetHandler(self, prog): + handler = None + _ = self._EnsureDispatch(prog) + if prog in self._handlers: + handler = self._handlers[prog] + return handler + +
[docs] def Dispatch(self, request, context): + prog = request.prog + dispatch = self._EnsureDispatch(prog) + # pylint: disable=protected-access + properties = [p for p in dispatch._prop_map_get_.keys()] + methods = [ + m + for m in dir(dispatch) + if not m.startswith("_") and m not in ["CLSID", "coclass_clsid"] + ] + response = CybosPlusProxyService_pb2.DispatchResponse() + response.prog = prog + response.properties.extend(properties) # pylint: disable=no-member + response.methods.extend(methods) # pylint: disable=no-member + return response
+ +
[docs] def Property(self, request, context): + prog = request.prog + dispatch = self._EnsureDispatch(prog) + name = request.name + value = getattr(dispatch, name) + response = CybosPlusProxyService_pb2.PropertyResponse() + AssignPrimitive(response.value, value) # pylint: disable=no-member + return response
+ +
[docs] def Method(self, request, context): + prog = request.prog + dispatch = self._EnsureDispatch(prog) + name = request.name + method = getattr(dispatch, name) + arguments = [ExtractPrimitive(arg.value) for arg in request.arguments] + return_value = method(*arguments) + response = CybosPlusProxyService_pb2.MethodResponse() + AssignPrimitive( + response.return_value, return_value + ) # pylint: disable=no-member + return response
+ +
[docs] def Event(self, request_iterator, context): + start_request = next(request_iterator) + assert start_request.HasField("start") + prog = start_request.start.prog + handler = self._GetHandler(prog) + response = CybosPlusProxyService_pb2.EventResponse() + response.started # pylint: disable=no-member,pointless-statement + yield response + for event in handler: + response = CybosPlusProxyService_pb2.EventResponse() + response.fired # pylint: disable=no-member,pointless-statement + yield response + done_request = next(request_iterator) + event.done() + if done_request.HasField("stop"): + break
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2.html new file mode 100644 index 00000000..8309c520 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2.html @@ -0,0 +1,1358 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2

+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: koapy/backend/cybos/CybosPlusProxyService.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
[docs]DESCRIPTOR = _descriptor.FileDescriptor( + name="koapy/backend/cybos/CybosPlusProxyService.proto", + package="", + syntax="proto3", + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n/koapy/backend/cybos/CybosPlusProxyService.proto"\x1f\n\x0f\x44ispatchRequest\x12\x0c\n\x04prog\x18\x01 \x01(\t"Q\n\x10\x44ispatchResponse\x12\x0c\n\x04prog\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x03(\t\x12\x0f\n\x07methods\x18\x03 \x03(\t\x12\n\n\x02id\x18\x04 \x01(\t"-\n\x0fPropertyRequest\x12\x0c\n\x04prog\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t"6\n\x13PrimitiveValueArray\x12\x1f\n\x06values\x18\x01 \x03(\x0b\x32\x0f.PrimitiveValue"\xcd\x01\n\x0ePrimitiveValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x14\n\nlong_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x12\x15\n\x0b\x66loat_value\x18\x04 \x01(\x01H\x00\x12*\n\nlist_value\x18\x05 \x01(\x0b\x32\x14.PrimitiveValueArrayH\x00\x12+\n\x0btuple_value\x18\x06 \x01(\x0b\x32\x14.PrimitiveValueArrayH\x00\x42\x07\n\x05value"2\n\x10PropertyResponse\x12\x1e\n\x05value\x18\x01 \x01(\x0b\x32\x0f.PrimitiveValue"*\n\x08\x41rgument\x12\x1e\n\x05value\x18\x01 \x01(\x0b\x32\x0f.PrimitiveValue"I\n\rMethodRequest\x12\x0c\n\x04prog\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1c\n\targuments\x18\x03 \x03(\x0b\x32\t.Argument"7\n\x0eMethodResponse\x12%\n\x0creturn_value\x18\x01 \x01(\x0b\x32\x0f.PrimitiveValue"!\n\x11\x45ventStartRequest\x12\x0c\n\x04prog\x18\x01 \x01(\t"9\n\x10\x45ventDoneRequest\x12%\n\x0creturn_value\x18\x01 \x01(\x0b\x32\x0f.PrimitiveValue"\x12\n\x10\x45ventStopRequest"s\n\x0c\x45ventRequest\x12!\n\x05start\x18\x01 \x01(\x0b\x32\x12.EventStartRequest\x12\x1f\n\x04\x64one\x18\x02 \x01(\x0b\x32\x11.EventDoneRequest\x12\x1f\n\x04stop\x18\x03 \x01(\x0b\x32\x11.EventStopRequest"\x16\n\x14\x45ventStartedResponse"\x14\n\x12\x45ventFiredResponse"k\n\rEventResponse\x12(\n\x07started\x18\x01 \x01(\x0b\x32\x15.EventStartedResponseH\x00\x12$\n\x05\x66ired\x18\x02 \x01(\x0b\x32\x13.EventFiredResponseH\x00\x42\n\n\x08response2\xd8\x01\n\x15\x43ybosPlusProxyService\x12\x31\n\x08\x44ispatch\x12\x10.DispatchRequest\x1a\x11.DispatchResponse"\x00\x12\x31\n\x08Property\x12\x10.PropertyRequest\x1a\x11.PropertyResponse"\x00\x12+\n\x06Method\x12\x0e.MethodRequest\x1a\x0f.MethodResponse"\x00\x12,\n\x05\x45vent\x12\r.EventRequest\x1a\x0e.EventResponse"\x00(\x01\x30\x01\x62\x06proto3', +)
+ + +_DISPATCHREQUEST = _descriptor.Descriptor( + name="DispatchRequest", + full_name="DispatchRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="prog", + full_name="DispatchRequest.prog", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=51, + serialized_end=82, +) + + +_DISPATCHRESPONSE = _descriptor.Descriptor( + name="DispatchResponse", + full_name="DispatchResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="prog", + full_name="DispatchResponse.prog", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="properties", + full_name="DispatchResponse.properties", + index=1, + number=2, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="methods", + full_name="DispatchResponse.methods", + index=2, + number=3, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="id", + full_name="DispatchResponse.id", + index=3, + number=4, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=84, + serialized_end=165, +) + + +_PROPERTYREQUEST = _descriptor.Descriptor( + name="PropertyRequest", + full_name="PropertyRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="prog", + full_name="PropertyRequest.prog", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="name", + full_name="PropertyRequest.name", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=167, + serialized_end=212, +) + + +_PRIMITIVEVALUEARRAY = _descriptor.Descriptor( + name="PrimitiveValueArray", + full_name="PrimitiveValueArray", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="values", + full_name="PrimitiveValueArray.values", + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=214, + serialized_end=268, +) + + +_PRIMITIVEVALUE = _descriptor.Descriptor( + name="PrimitiveValue", + full_name="PrimitiveValue", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="string_value", + full_name="PrimitiveValue.string_value", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="long_value", + full_name="PrimitiveValue.long_value", + index=1, + number=2, + type=3, + cpp_type=2, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="bool_value", + full_name="PrimitiveValue.bool_value", + index=2, + number=3, + type=8, + cpp_type=7, + label=1, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="float_value", + full_name="PrimitiveValue.float_value", + index=3, + number=4, + type=1, + cpp_type=5, + label=1, + has_default_value=False, + default_value=float(0), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="list_value", + full_name="PrimitiveValue.list_value", + index=4, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="tuple_value", + full_name="PrimitiveValue.tuple_value", + index=5, + number=6, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="value", + full_name="PrimitiveValue.value", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=271, + serialized_end=476, +) + + +_PROPERTYRESPONSE = _descriptor.Descriptor( + name="PropertyResponse", + full_name="PropertyResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="value", + full_name="PropertyResponse.value", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=478, + serialized_end=528, +) + + +_ARGUMENT = _descriptor.Descriptor( + name="Argument", + full_name="Argument", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="value", + full_name="Argument.value", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=530, + serialized_end=572, +) + + +_METHODREQUEST = _descriptor.Descriptor( + name="MethodRequest", + full_name="MethodRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="prog", + full_name="MethodRequest.prog", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="name", + full_name="MethodRequest.name", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="arguments", + full_name="MethodRequest.arguments", + index=2, + number=3, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=574, + serialized_end=647, +) + + +_METHODRESPONSE = _descriptor.Descriptor( + name="MethodResponse", + full_name="MethodResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="return_value", + full_name="MethodResponse.return_value", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=649, + serialized_end=704, +) + + +_EVENTSTARTREQUEST = _descriptor.Descriptor( + name="EventStartRequest", + full_name="EventStartRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="prog", + full_name="EventStartRequest.prog", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=706, + serialized_end=739, +) + + +_EVENTDONEREQUEST = _descriptor.Descriptor( + name="EventDoneRequest", + full_name="EventDoneRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="return_value", + full_name="EventDoneRequest.return_value", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=741, + serialized_end=798, +) + + +_EVENTSTOPREQUEST = _descriptor.Descriptor( + name="EventStopRequest", + full_name="EventStopRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=800, + serialized_end=818, +) + + +_EVENTREQUEST = _descriptor.Descriptor( + name="EventRequest", + full_name="EventRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="start", + full_name="EventRequest.start", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="done", + full_name="EventRequest.done", + index=1, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="stop", + full_name="EventRequest.stop", + index=2, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=820, + serialized_end=935, +) + + +_EVENTSTARTEDRESPONSE = _descriptor.Descriptor( + name="EventStartedResponse", + full_name="EventStartedResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=937, + serialized_end=959, +) + + +_EVENTFIREDRESPONSE = _descriptor.Descriptor( + name="EventFiredResponse", + full_name="EventFiredResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=961, + serialized_end=981, +) + + +_EVENTRESPONSE = _descriptor.Descriptor( + name="EventResponse", + full_name="EventResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="started", + full_name="EventResponse.started", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="fired", + full_name="EventResponse.fired", + index=1, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="response", + full_name="EventResponse.response", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=983, + serialized_end=1090, +) + +_PRIMITIVEVALUEARRAY.fields_by_name["values"].message_type = _PRIMITIVEVALUE +_PRIMITIVEVALUE.fields_by_name["list_value"].message_type = _PRIMITIVEVALUEARRAY +_PRIMITIVEVALUE.fields_by_name["tuple_value"].message_type = _PRIMITIVEVALUEARRAY +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["string_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "string_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["long_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "long_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["bool_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "bool_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["float_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "float_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["list_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "list_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PRIMITIVEVALUE.oneofs_by_name["value"].fields.append( + _PRIMITIVEVALUE.fields_by_name["tuple_value"] +) +_PRIMITIVEVALUE.fields_by_name[ + "tuple_value" +].containing_oneof = _PRIMITIVEVALUE.oneofs_by_name["value"] +_PROPERTYRESPONSE.fields_by_name["value"].message_type = _PRIMITIVEVALUE +_ARGUMENT.fields_by_name["value"].message_type = _PRIMITIVEVALUE +_METHODREQUEST.fields_by_name["arguments"].message_type = _ARGUMENT +_METHODRESPONSE.fields_by_name["return_value"].message_type = _PRIMITIVEVALUE +_EVENTDONEREQUEST.fields_by_name["return_value"].message_type = _PRIMITIVEVALUE +_EVENTREQUEST.fields_by_name["start"].message_type = _EVENTSTARTREQUEST +_EVENTREQUEST.fields_by_name["done"].message_type = _EVENTDONEREQUEST +_EVENTREQUEST.fields_by_name["stop"].message_type = _EVENTSTOPREQUEST +_EVENTRESPONSE.fields_by_name["started"].message_type = _EVENTSTARTEDRESPONSE +
[docs]_EVENTRESPONSE.fields_by_name["fired"].message_type = _EVENTFIREDRESPONSE
+_EVENTRESPONSE.oneofs_by_name["response"].fields.append( + _EVENTRESPONSE.fields_by_name["started"] +) +_EVENTRESPONSE.fields_by_name[ + "started" +].containing_oneof = _EVENTRESPONSE.oneofs_by_name["response"] +_EVENTRESPONSE.oneofs_by_name["response"].fields.append( + _EVENTRESPONSE.fields_by_name["fired"] +) +
[docs]_EVENTRESPONSE.fields_by_name["fired"].containing_oneof = _EVENTRESPONSE.oneofs_by_name[ + "response" +]
+DESCRIPTOR.message_types_by_name["DispatchRequest"] = _DISPATCHREQUEST +DESCRIPTOR.message_types_by_name["DispatchResponse"] = _DISPATCHRESPONSE +DESCRIPTOR.message_types_by_name["PropertyRequest"] = _PROPERTYREQUEST +DESCRIPTOR.message_types_by_name["PrimitiveValueArray"] = _PRIMITIVEVALUEARRAY +DESCRIPTOR.message_types_by_name["PrimitiveValue"] = _PRIMITIVEVALUE +DESCRIPTOR.message_types_by_name["PropertyResponse"] = _PROPERTYRESPONSE +DESCRIPTOR.message_types_by_name["Argument"] = _ARGUMENT +DESCRIPTOR.message_types_by_name["MethodRequest"] = _METHODREQUEST +DESCRIPTOR.message_types_by_name["MethodResponse"] = _METHODRESPONSE +DESCRIPTOR.message_types_by_name["EventStartRequest"] = _EVENTSTARTREQUEST +DESCRIPTOR.message_types_by_name["EventDoneRequest"] = _EVENTDONEREQUEST +DESCRIPTOR.message_types_by_name["EventStopRequest"] = _EVENTSTOPREQUEST +DESCRIPTOR.message_types_by_name["EventRequest"] = _EVENTREQUEST +DESCRIPTOR.message_types_by_name["EventStartedResponse"] = _EVENTSTARTEDRESPONSE +DESCRIPTOR.message_types_by_name["EventFiredResponse"] = _EVENTFIREDRESPONSE +DESCRIPTOR.message_types_by_name["EventResponse"] = _EVENTRESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +
[docs]DispatchRequest = _reflection.GeneratedProtocolMessageType( + "DispatchRequest", + (_message.Message,), + { + "DESCRIPTOR": _DISPATCHREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:DispatchRequest) + }, +)
+_sym_db.RegisterMessage(DispatchRequest) + +
[docs]DispatchResponse = _reflection.GeneratedProtocolMessageType( + "DispatchResponse", + (_message.Message,), + { + "DESCRIPTOR": _DISPATCHRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:DispatchResponse) + }, +)
+_sym_db.RegisterMessage(DispatchResponse) + +
[docs]PropertyRequest = _reflection.GeneratedProtocolMessageType( + "PropertyRequest", + (_message.Message,), + { + "DESCRIPTOR": _PROPERTYREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:PropertyRequest) + }, +)
+_sym_db.RegisterMessage(PropertyRequest) + +
[docs]PrimitiveValueArray = _reflection.GeneratedProtocolMessageType( + "PrimitiveValueArray", + (_message.Message,), + { + "DESCRIPTOR": _PRIMITIVEVALUEARRAY, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:PrimitiveValueArray) + }, +)
+_sym_db.RegisterMessage(PrimitiveValueArray) + +
[docs]PrimitiveValue = _reflection.GeneratedProtocolMessageType( + "PrimitiveValue", + (_message.Message,), + { + "DESCRIPTOR": _PRIMITIVEVALUE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:PrimitiveValue) + }, +)
+_sym_db.RegisterMessage(PrimitiveValue) + +
[docs]PropertyResponse = _reflection.GeneratedProtocolMessageType( + "PropertyResponse", + (_message.Message,), + { + "DESCRIPTOR": _PROPERTYRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:PropertyResponse) + }, +)
+_sym_db.RegisterMessage(PropertyResponse) + +
[docs]Argument = _reflection.GeneratedProtocolMessageType( + "Argument", + (_message.Message,), + { + "DESCRIPTOR": _ARGUMENT, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:Argument) + }, +)
+_sym_db.RegisterMessage(Argument) + +
[docs]MethodRequest = _reflection.GeneratedProtocolMessageType( + "MethodRequest", + (_message.Message,), + { + "DESCRIPTOR": _METHODREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:MethodRequest) + }, +)
+_sym_db.RegisterMessage(MethodRequest) + +
[docs]MethodResponse = _reflection.GeneratedProtocolMessageType( + "MethodResponse", + (_message.Message,), + { + "DESCRIPTOR": _METHODRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:MethodResponse) + }, +)
+_sym_db.RegisterMessage(MethodResponse) + +
[docs]EventStartRequest = _reflection.GeneratedProtocolMessageType( + "EventStartRequest", + (_message.Message,), + { + "DESCRIPTOR": _EVENTSTARTREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventStartRequest) + }, +)
+_sym_db.RegisterMessage(EventStartRequest) + +
[docs]EventDoneRequest = _reflection.GeneratedProtocolMessageType( + "EventDoneRequest", + (_message.Message,), + { + "DESCRIPTOR": _EVENTDONEREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventDoneRequest) + }, +)
+_sym_db.RegisterMessage(EventDoneRequest) + +
[docs]EventStopRequest = _reflection.GeneratedProtocolMessageType( + "EventStopRequest", + (_message.Message,), + { + "DESCRIPTOR": _EVENTSTOPREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventStopRequest) + }, +)
+_sym_db.RegisterMessage(EventStopRequest) + +
[docs]EventRequest = _reflection.GeneratedProtocolMessageType( + "EventRequest", + (_message.Message,), + { + "DESCRIPTOR": _EVENTREQUEST, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventRequest) + }, +)
+_sym_db.RegisterMessage(EventRequest) + +
[docs]EventStartedResponse = _reflection.GeneratedProtocolMessageType( + "EventStartedResponse", + (_message.Message,), + { + "DESCRIPTOR": _EVENTSTARTEDRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventStartedResponse) + }, +)
+_sym_db.RegisterMessage(EventStartedResponse) + +
[docs]EventFiredResponse = _reflection.GeneratedProtocolMessageType( + "EventFiredResponse", + (_message.Message,), + { + "DESCRIPTOR": _EVENTFIREDRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventFiredResponse) + }, +)
+_sym_db.RegisterMessage(EventFiredResponse) + +
[docs]EventResponse = _reflection.GeneratedProtocolMessageType( + "EventResponse", + (_message.Message,), + { + "DESCRIPTOR": _EVENTRESPONSE, + "__module__": "koapy.backend.cybos.CybosPlusProxyService_pb2" + # @@protoc_insertion_point(class_scope:EventResponse) + }, +)
+_sym_db.RegisterMessage(EventResponse) + + +_CYBOSPLUSPROXYSERVICE = _descriptor.ServiceDescriptor( + name="CybosPlusProxyService", + full_name="CybosPlusProxyService", + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=1093, + serialized_end=1309, + methods=[ + _descriptor.MethodDescriptor( + name="Dispatch", + full_name="CybosPlusProxyService.Dispatch", + index=0, + containing_service=None, + input_type=_DISPATCHREQUEST, + output_type=_DISPATCHRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name="Property", + full_name="CybosPlusProxyService.Property", + index=1, + containing_service=None, + input_type=_PROPERTYREQUEST, + output_type=_PROPERTYRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name="Method", + full_name="CybosPlusProxyService.Method", + index=2, + containing_service=None, + input_type=_METHODREQUEST, + output_type=_METHODRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name="Event", + full_name="CybosPlusProxyService.Event", + index=3, + containing_service=None, + input_type=_EVENTREQUEST, + output_type=_EVENTRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + ], +) +_sym_db.RegisterServiceDescriptor(_CYBOSPLUSPROXYSERVICE) + +DESCRIPTOR.services_by_name["CybosPlusProxyService"] = _CYBOSPLUSPROXYSERVICE + +# @@protoc_insertion_point(module_scope) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc.html b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc.html new file mode 100644 index 00000000..7f2990c0 --- /dev/null +++ b/_modules/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc.html @@ -0,0 +1,358 @@ + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc

+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from koapy.backend.daishin_cybos_plus.proxy import (
+    CybosPlusProxyService_pb2 as koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2,
+)
+
+
+
[docs]class CybosPlusProxyServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Dispatch = channel.unary_unary( + "/CybosPlusProxyService/Dispatch", + request_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchResponse.FromString, + ) + self.Property = channel.unary_unary( + "/CybosPlusProxyService/Property", + request_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyResponse.FromString, + ) + self.Method = channel.unary_unary( + "/CybosPlusProxyService/Method", + request_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodResponse.FromString, + ) + self.Event = channel.stream_stream( + "/CybosPlusProxyService/Event", + request_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventResponse.FromString, + )
+ + +
[docs]class CybosPlusProxyServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + +
[docs] def Dispatch(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!")
+ +
[docs] def Property(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!")
+ +
[docs] def Method(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!")
+ +
[docs] def Event(self, request_iterator, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!")
+ + +
[docs]def add_CybosPlusProxyServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + "Dispatch": grpc.unary_unary_rpc_method_handler( + servicer.Dispatch, + request_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchRequest.FromString, + response_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchResponse.SerializeToString, + ), + "Property": grpc.unary_unary_rpc_method_handler( + servicer.Property, + request_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyRequest.FromString, + response_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyResponse.SerializeToString, + ), + "Method": grpc.unary_unary_rpc_method_handler( + servicer.Method, + request_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodRequest.FromString, + response_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodResponse.SerializeToString, + ), + "Event": grpc.stream_stream_rpc_method_handler( + servicer.Event, + request_deserializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventRequest.FromString, + response_serializer=koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "CybosPlusProxyService", rpc_method_handlers + ) + server.add_generic_rpc_handlers((generic_handler,))
+ + +# This class is part of an EXPERIMENTAL API. +
[docs]class CybosPlusProxyService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod +
[docs] def Dispatch( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/CybosPlusProxyService/Dispatch", + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchRequest.SerializeToString, + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.DispatchResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + )
+ + @staticmethod +
[docs] def Property( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/CybosPlusProxyService/Property", + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyRequest.SerializeToString, + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.PropertyResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + )
+ + @staticmethod +
[docs] def Method( + request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.unary_unary( + request, + target, + "/CybosPlusProxyService/Method", + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodRequest.SerializeToString, + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.MethodResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + )
+ + @staticmethod +
[docs] def Event( + request_iterator, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None, + ): + return grpc.experimental.stream_stream( + request_iterator, + target, + "/CybosPlusProxyService/Event", + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventRequest.SerializeToString, + koapy_dot_backend_dot_cybos_dot_CybosPlusProxyService__pb2.EventResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.html new file mode 100644 index 00000000..90e02158 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.html @@ -0,0 +1,355 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition

+import contextlib
+
+from os import PathLike
+from pathlib import Path
+from typing import Optional, Sequence, TextIO, Union
+
+
+
[docs]class KiwoomOpenApiPlusConditionEntry: + def __init__( + self, + header, + item_id, + group_id, + group_name, + group_tp, + name, + group_id_small, + order_no, + type_position, + upjong, + portfolio, + recommend, + acc, + group, + excepts, + month, + exp, + count, + rules, + ): + self.header = header + self.item_id = item_id + self.group_id = group_id + self.group_name = group_name + self.group_tp = group_tp + self.name = name + self.group_id_small = group_id_small + self.order_no = order_no + self.type_position = type_position + self.upjong = upjong + self.portfolio = portfolio + self.recommend = recommend + self.acc = acc + self.group = group + self.excepts = excepts + self.month = month + self.exp = exp + self.count = count + self.rules = rules + + def __repr__(self): + template = "{}" + "({})".format(", ".join(["{!r}" for _ in range(19)])) + return template.format( + self.__class__.__name__, + self.header, + self.item_id, + self.group_id, + self.group_name, + self.group_tp, + self.name, + self.group_id_small, + self.order_no, + self.type_position, + self.upjong, + self.portfolio, + self.recommend, + self.acc, + self.group, + self.excepts, + self.month, + self.exp, + self.count, + self.rules, + ) + + @classmethod +
[docs] def from_datfile(cls, f: TextIO): + lines = iter(f) + lines = map(lambda line: line.rstrip("\n"), lines) + line = next(lines) + while line == "": + line = next(lines) + assert line.startswith("[") and line.endswith("]") + header = line + line = next(lines) + assert line.startswith("ItemID=") + item_id = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("GroupID=") + group_id = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("GroupName=") + group_name = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("GroupTp=") + group_tp = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Name=") + name = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("GroupId=") + group_id_small = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("OrderNo=") + order_no = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("TypePosition=") + type_position = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Upjong=") + upjong = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Portfolio=") + portfolio = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Recommend=") + recommend = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Acc=") + acc = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Group=") + group = line.split("=", 2)[1] + excepts = [] + for i in range(22): + line = next(lines) + assert line.startswith(f"Except{i+1}=") + except_item = line.split("=", 2)[1] + excepts.append(except_item) + line = next(lines) + assert line.startswith("Month=") + month = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Exp=") + exp = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("Count=") + count = line.split("=", 2)[1] + count = int(count) + rules = [] + for i in range(count): + line = next(lines) + assert line.startswith(f"{str(i).zfill(2)}=") + rule_num, rule_expr = line.split("=", 2) + rule = (rule_num, rule_expr) + rules.append(rule) + return cls( + header, + item_id, + group_id, + group_name, + group_tp, + name, + group_id_small, + order_no, + type_position, + upjong, + portfolio, + recommend, + acc, + group, + excepts, + month, + exp, + count, + rules, + )
+ + +
[docs]class KiwoomOpenApiPlusConditionFile: + def __init__( + self, version: str, entries: Sequence[KiwoomOpenApiPlusConditionEntry] + ): + self.version = version + self.entries = list(entries) + + def __repr__(self): + template = "{}" + "({})".format(", ".join(["{!r}" for _ in range(2)])) + return template.format( + self.__class__.__name__, + self.version, + self.entries, + ) + + @classmethod +
[docs] def from_datfile( + cls, f: Union[str, PathLike, TextIO], encoding: Optional[str] = None + ): + if isinstance(f, str): + f = Path(f) + if encoding is None: + encoding = "euc-kr" + with contextlib.ExitStack() as stack: + if isinstance(f, PathLike): + f = open(f, "r", encoding=encoding) + f = stack.enter_context(f) + lines = iter(f) + lines = map(lambda line: line.rstrip("\n"), lines) + line = next(lines) + assert line == "[Version]" + line = next(lines) + assert line.startswith("ver=") + version = line.split("=", 2)[1] + entries = [] + should_stop = False + while not should_stop: + try: + cond = KiwoomOpenApiPlusConditionEntry.from_datfile(f) + except StopIteration: + break + else: + entries.append(cond) + return cls(version, entries)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.html new file mode 100644 index 00000000..4aad3b24 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.html @@ -0,0 +1,1381 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions

+
[docs]class KiwoomOpenApiPlusDispatchFunctions: +
[docs] def CommConnect(self) -> int: + """ + 로그인 윈도우를 실행한다. + + 수동 로그인 설정인 경우 로그인창을 출력. + 자동 로그인 설정인 경우 로그인창에서 자동으로 로그인을 시도합니다. + + 로그인이 성공하거나 실패하는 경우 OnEventConnect() 이벤트가 발생하고 이벤트의 + 인자 값으로 로그인 성공 여부를 알 수 있다. + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def CommTerminate(self) -> None: + """ + 더 이상 지원하지 않는 함수. + + 프로그램 종료없이 서버와의 접속만 단절시키는 함수입니다. + ※ 함수 사용 후 사용자의 오해소지가 생기는 이유로 더 이상 사용할 수 없는 함수입니다. + + 통신 연결 상태는 GetConnectState() 메소드로 알 수 있다. + """ + ...
+ +
[docs] def CommRqData( + self, sRQName: str, sTrCode: str, nPrevNext: int, sScreenNo: str + ) -> int: + """ + 통신 데이터를 서버로 전송한다. + + 반환 코드 구분: + - OP_ERR_NONE(0): 정상처리 + - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 + - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 + - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 + + Args: + sRQName (str): 사용자 구분명 (임의로 지정, 한글 지원) + sTrCode (str): 조회하려는 TR 코드 + nPrevNext (int): 연속조회 여부 (0:조회, 2:연속) + sScreenNo (str): 화면번호 (4자리 숫자 임의로 지정) + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def GetLoginInfo(self, sTag: str) -> str: + """ + 로그인한 사용자 정보를 반환한다. + + 태그값 구분: + - "ACCOUNT_CNT": 전체 보유계좌 개수를 반환합니다. + - "ACCLIST" 또는 "ACCNO": 구분자 ';' 로 연결된 전체 보유계좌 목록을 반환합니다. + - "USER_ID": 사용자 ID를 반환합니다. + - "USER_NAME": 사용자 이름을 반환합니다. + - "KEY_BSECGB": 키보드 보안 해지 여부를 반환합니다. (0:정상, 1:해지) + - "FIREW_SECGB": 방화벽 설정 여부를 반환합니다. (0:미설정, 1:설정, 2:해지) + - "GetServerGubun": 접속서버 구분을 반환합니다. (1:모의투자, 나머지:실거래서버) + + Args: + sTag (str): 사용자 정보 구분 태그 값 + + Returns: + str: 태그값에 따른 데이터 반환 + """ + ...
+ +
[docs] def SendOrder( + self, + sRQName: str, + sScreenNo: str, + sAccNo: str, + nOrderType: int, + sCode: str, + nQty: int, + nPrice: int, + sHogaGb: str, + sOrgOrderNo: str, + ) -> int: + """ + 주식 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 9개 인자값을 가진 주식주문 함수이며 리턴값이 0이면 성공이며 나머지는 에러입니다. + 1초에 5회만 주문가능하며 그 이상 주문요청하면 에러 -308을 리턴합니다. + + ※ 시장가, 최유리지정가, 최우선지정가, 시장가IOC, 최유리IOC, 시장가FOK, 최유리FOK, 장전시간외, 장후시간외 주문시 주문가격은 0으로 입력합니다. + ※ 취소 주문일때 주문가격은 0으로 입력합니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 정규장 외 주문: + - 장전 동시호가 주문 + - 08:30 ~ 09:00. 거래구분 00:지정가/03:시장가 (일반주문처럼) + - ※ 08:20 ~ 08:30 시간의 주문은 키움에서 대기하여 08:30 에 순서대로 거래소로 전송합니다. + - 장전시간외 종가 + - 08:30 ~ 08:40. 거래구분 61:장전시간외종가. 가격 0입력 + - ※ 전일 종가로 거래. 미체결시 자동취소되지 않음 + - 장마감 동시호가 주문 + - 15:20 ~ 15:30. 거래구분 00:지정가/03:시장가 (일반주문처럼) + - 장후 시간외 종가 + - 15:40 ~ 16:00. 거래구분 81:장후시간외종가. 가격 0입력 + - ※ 당일 종가로 거래 + - 시간외 단일가 + - 16:00 ~ 18:00. 거래구분 62:시간외단일가. 가격 입력 + - ※ 10분 단위로 체결, 당일 종가대비 +-10% 가격으로 거래 + + 주문 유형: + - 1: 신규매수 + - 2: 신규매도 + - 3: 매수취소 + - 4: 매도취소 + - 5: 매수정정 + - 6: 매도정정 + + Args: + sRQName (str): 사용자 구분 요청명 + sScreenNo (str): 화면번호 (4자리) + sAccNo (str): 계좌번호 (10자리) + nOrderType (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + sCode (str): 종목코드 (6자리) + nQty (int): 주문수량 + nPrice (int): 주문단가 + sHogaGb (str): 거래구분 (혹은 호가구분) + sOrgOrderNo (str): 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def SendOrderFO( + self, + sRQName: str, + sScreenNo: str, + sAccNo: str, + sCode: str, + lOrdKind: int, + sSlbyTp: str, + sOrdTp: str, + lQty: int, + sPrice: str, + sOrgOrdNo: str, + ) -> int: + """ + 선물/옵션 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 코스피지수200 선물옵션 전용 주문함수입니다. + + 거래 구분: + - 1: 지정가 + - 2: 조건부지정가 + - 3: 시장가 + - 4: 최유리지정가 + - 5: 지정가(IOC) + - 6: 지정가(FOK) + - 7: 시장가(IOC) + - 8: 시장가(FOK) + - 9: 최유리지정가(IOC) + - A: 최유리지정가(FOK) + + ※ 장종료 후 시간외 주문은 지정가 선택 + + Args: + sRQName (str): 사용자 구분명 + sScreenNo (str): 화면번호 + sAccNo (str): 계좌번호 (10자리) + sCode (str): 종목코드 + lOrdKind (int): 주문종류 (1:신규매매, 2:정정, 3:취소) + sSlbyTp (str): 매매구분 (1:매도, 2:매수) + sOrdTp (str): 거래구분 + lQty (int): 주문수량 + sPrice (str): 주문가격 + sOrgOrdNo (str): 원주문번호 + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def SetInputValue(self, sID: str, sValue: str) -> None: + """ + TR 입력 값을 서버통신 전에 입력한다. + + 조회요청시 TR의 Input값을 지정하는 함수입니다. + CommRqData() 호출 전에 입력값들을 셋팅합니다. + 각 TR마다 Input 항목이 다릅니다. 순서에 맞게 Input 값들을 셋팅해야 합니다. + + Args: + sID (str): TR에 명시된 Input 이름 + sValue (str): Input 이름으로 지정한 값 + """ + ...
+ +
[docs] def SetOutputFID(self, sID: str) -> int: + """ + 1.0.0.1 버전 이후 사용하지 않음. + """ + ...
+ +
[docs] def CommGetData( + self, + sJongmokCode: str, + sRealType: str, + sFieldName: str, + nIndex: int, + sInnerFieldName: str, + ) -> str: + """ + 이 함수는 지원하지 않을 것이므로 용도에 맞는 전용 함수를 사용할 것. (비고참고) + + 일부 TR에서 사용상 제약이 있으므로 이 함수 대신 GetCommData() 함수를 사용하시기 바랍니다. + + 비고: + - 조회 정보 요청: GetCommData(strTrCode: str, strRecordName: str, nIndex: int, strItemName: str) + - 실시간 정보 요청: GetCommRealData(sTrCode: str, nFid: int) + - 체결 정보 요청: GetChejanData(nFid: int) + """ + ...
+ +
[docs] def DisconnectRealData(self, sScnNo: str) -> None: + """ + 화면 내 모든 리얼데이터 요청을 제거한다. + + 시세데이터를 요청할때 사용된 화면번호를 이용하여 + 해당 화면번호로 등록되어져 있는 종목의 실시간시세를 서버에 등록해지 요청합니다. + 이후 해당 종목의 실시간시세는 수신되지 않습니다. + 단, 해당 종목이 또다른 화면번호로 실시간 등록되어 있는 경우 해당종목에대한 실시간시세 데이터는 계속 수신됩니다. + + 화면을 종료할 때 반드시 위 함수를 호출해야 한다. + + Args: + sScnNo: 화면번호 (4자리) + """ + ...
+ +
[docs] def GetRepeatCnt(self, sTrCode: str, sRecordName: str) -> int: + """ + 레코드 반복횟수를 반환한다. + + 데이터 수신시 멀티데이터의 갯수(반복수)를 얻을수 있습니다. + 예를 들어 차트조회는 한번에 최대 900개 데이터를 수신할 수 있는데 + 이렇게 수신한 데이터갯수를 얻을때 사용합니다. + 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + + Args: + sTrCode (str): TR 이름 + sRecordName (str): 레코드 이름 + + Returns: + int: 레코드의 반복횟수 + """ + ...
+ +
[docs] def CommKwRqData( + self, + sArrCode: str, + bNext: int, + nCodeCount: int, + nTypeFlag: int, + sRQName: str, + sScreenNo: str, + ) -> int: + """ + 복수종목조회 요청을 서버로 송신한다. + + 한번에 100종목까지 조회할 수 있는 복수종목 조회함수 입니다. + 함수인자로 사용하는 종목코드 리스트는 조회하려는 종목코드 사이에 구분자 ';' 를 추가해서 만들면 됩니다. + 수신되는 데이터는 TR목록에서 복수종목정보요청(OPTKWFID) Output을 참고하시면 됩니다. + + ※ OPTKWFID TR은 CommKwRqData() 함수 전용으로, CommRqData 로는 사용할 수 없습니다. + ※ OPTKWFID TR은 영웅문4 HTS의 관심종목과는 무관합니다. + + 반환 코드 구분: + - OP_ERR_NONE(0): 정상처리 + - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 + - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 + - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 + + Args: + sArrCode (str): 종목리스트 + bNext (int): 연속조회 여부 (0:기본값, 1:연속조회(지원안함)) + nCodeCount (int): 종목개수 + nTypeFlag (int): 조회구분 (0:주식 종목, 3:선물옵션 종목) + sRQName (str): 사용자 구분명 + sScreenNo (str): 화면번호 (4자리) + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def GetAPIModulePath(self) -> str: + """ + OpenAPI 모듈의 경로를 반환한다. + + Returns: + str: OpenAPI 모듈의 설치 경로 + """ + ...
+ +
[docs] def GetCodeListByMarket(self, sMarket: str) -> str: + """ + 시장구분에 따른 종목코드를 반환한다. + + 주식 시장별 종목코드 리스트를 ';' 로 구분해서 전달합니다. + 시장구분값을 "" 공백으로 하면 전체시장 코드리스트를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 시장 구분: + - 0: 장내 + - 3: ELW + - 4: 뮤추얼펀드 + - 5: 신주인수권 + - 6: 리츠 + - 8: ETF + - 9: 하이일드펀드 + - 10: 코스닥 + - 30: K-OTC + - 50: 코넥스 (KONEX) + + Args: + sMarket (str): 시장 구분값 + + Returns: + str: 종목코드 리스트, 종목간 구분은 ';' 이다. + """ + ...
+ +
[docs] def GetConnectState(self) -> int: + """ + 현재 접속상태를 반환한다. + + 서버와 현재 접속 상태를 알려줍니다. + + Returns: + int: 접속상태, 1:연결, 0:연결안됨 + """ + ...
+ +
[docs] def GetMasterCodeName(self, sTrCode: str) -> str: + """ + 종목코드의 한글명을 반환한다. + + 종목코드에 해당하는 종목명을 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 장내외, 지수선옵, 주식선옵 검색 가능. + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + str: 종목 한글명 + """ + ...
+ +
[docs] def GetMasterListedStockCnt(self, sTrCode: str) -> int: + """ + 종목코드의 상장주식수를 반환한다. + + 입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + int: 상장주식수 + """ + ...
+ +
[docs] def GetMasterConstruction(self, sTrCode: str) -> str: + """ + 종목코드의 감리구분을 반환한다. + + 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. + (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 감리 구분: + - 정상 + - 투자주의 + - 투자경고 + - 투자위험 + - 투자주의환기종목 + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + str: 감리구분 (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + """ + ...
+ +
[docs] def GetMasterListedStockDate(self, sTrCode: str) -> str: + """ + 종목코드의 상장일을 반환한다. + + 입력한 종목의 상장일을 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + str: 상장일 (8자리, YYYYMMDD) + """ + ...
+ +
[docs] def GetMasterLastPrice(self, sTrCode: str) -> str: + """ + 종목코드의 전일가를 반환한다. + + 입력한 종목의 당일 기준가를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + str: 전일가 + """ + ...
+ +
[docs] def GetMasterStockState(self, sTrCode: str) -> str: + """ + 종목코드의 종목상태를 반환한다. + + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + Args: + sTrCode (str): 종목코드 (4자리) + + Returns: + str: 종목상태 (정상, 증거금N%, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능) + """ + ...
+ +
[docs] def GetDataCount(self, strRecordName: str) -> int: + """ + 레코드의 반복개수를 반환한다. + + ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 + 해당 함수 대신 GetRepeatCnt() 를 사용하는게 더 바람직할 듯 + + Args: + strRecordName (str): 레코드 명 + + Returns: + str: 레코드 반복개수 + """ + ...
+ +
[docs] def GetOutputValue(self, strRecordName: str, nRepeatIdx: int, nItemIdx: int) -> str: + """ + 레코드의 반복순서와 아이템의 출력순서에 따라 수신데이터를 반환한다. + + ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 + 해당 함수 대신 GetCommData() 를 사용하는게 더 바람직할 듯 + + Args: + strRecordName (str): 레코드 명 + nRepeatIdx (int): 반복 순서 + nItemIdx (int): 아이템 순서 + + Returns: + str: 수신 데이터 + """ + ...
+ +
[docs] def GetCommData( + self, strTrCode: str, strRecordName: str, nIndex: int, strItemName: str + ) -> str: + """ + 수신 데이터를 반환한다. + + OnReceiveTRData() 이벤트가 발생될때 수신한 데이터를 얻어오는 함수입니다. + 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + + Args: + strTrCode (str): TR코드 + strRecordName (str): 레코드명 + nIndex (int): 복수데이터 인덱스 + strItemName (str): 아이템명 (TR별 출력항목 이름) + + Returns: + str: 수신 데이터 + """ + ...
+ +
[docs] def GetCommRealData(self, sTrCode: str, nFid: int) -> str: + """ + 실시간 시세 데이터를 반환한다. + + 실시간시세 데이터 수신 이벤트인 OnReceiveRealData() 가 발생될때 실시간데이터를 얻어오는 함수입니다. + 이 함수는 OnReceiveRealData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + FID 값은 KOAStudio 의 "실시간목록" 탭에서 확인할 수 있습니다. + + 일반적으로 strTrCode 는 OnReceiveRealData() 이벤트 함수의 첫번째 매개변수를 사용한다. + + Args: + strTrCode (str): TR코드 + nFid (int): 실시간 아이템 + + Returns: + str: 수신 데이터 + """ + ...
+ +
[docs] def GetChejanData(self, nFid: int) -> str: + """ + 체결잔고 데이터를 반환한다. + + OnReceiveChejan() 이벤트가 발생될때 FID 에 해당되는 값을 구하는 함수입니다. + 이 함수는 OnReceiveChejan() 이벤트 안에서 사용해야 합니다. + Ex) 체결가 = GetChejanData(910) + + Args: + nFid (int): 체결잔고 아이템 + + Returns: + str: 수신 데이터 + """ + ...
+ +
[docs] def GetThemeGroupList(self, nType: int) -> str: + """ + 테마코드와 테마명을 반환한다. + + 반환값의 코드와 코드명 구분은 '|', 코드의 구분은 ';' + Ex) 100|태양광_폴리실리콘;152|합성섬유 + + Args: + nType (int): 정렬순서 (0:코드순, 1:테마순) + + Returns: + str: 코드와 코드명 리스트 + """ + ...
+ +
[docs] def GetThemeGroupCode(self, strThemeCode: str) -> str: + """ + 테마코드에 소속된 종목코드를 반환한다. + + 반환값의 종목코드간 구분은 ';' + Ex) A000660;A005930 + + Args: + strThemeCode (str): 테마코드 + + Returns: + str: 종목코드 리스트 + """ + ...
+ +
[docs] def GetFutureList(self) -> str: + """ + 지수선물 리스트를 반환한다. + + 지수선물 종목코드 리스트를 ';'로 구분해서 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 반환값의 종목코드간 구분은 ';' + Ex) 101J9000;101JC000 + + Returns: + str: 종목코드 리스트 + """ + ...
+ +
[docs] def GetFutureCodeByIndex(self, nIndex: int) -> str: + """ + 지수선물 코드를 반환한다. + + Ex) 최근월선물 = GetFutureCodeByIndex(0) + 최근월스프레드 = GetFutureCodeByIndex(4) + + Args: + nIndex (int): 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드 + + Returns: + str: 종목코드 + """ + ...
+ +
[docs] def GetActPriceList(self) -> str: + """ + 지수옵션 행사가 리스트를 반환한다. + + 지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ';' 로 구분해서 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + ※ PDF 문서상의 예시에서는 소수점 아래가 존재하는 예시지만, KOAStudio 의 설명과 예시에서는 그렇지 않음. + 아마도 KOAStudio 의 설명을 따르는게 더 바람직할 듯. + + Returns: + str: 행사가 + """ + ...
+ +
[docs] def GetMonthList(self) -> str: + """ + 지수옵션 월물 리스트를 반환한다. + + 지수옵션 월물정보를 ';' 로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 반환값의 월물간 구분은 ';' + Ex) 201412;201409;201408;201407;201407;201408;201409;201412 + + Returns: + str: 월물 (YYYYMM;YYYYMM;...) + """ + ...
+ +
[docs] def GetOptionCode(self, strActPrice: str, nCp: int, strMonth: str) -> str: + """ + 행사가와 월물 콜풋으로 종목코드를 구한다. + + 인자로 지정한 지수옵션 코드를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + Args: + strActPrice (str): 행사가 (소수점 포함) + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + strMonth (str): 월물 (6자리, YYYYMM) + + Returns: + str: 종목코드 + + Examples: + >>> GetOptionCode("260.00", 2, "201407") + """ + ...
+ +
[docs] def GetOptionCodeByMonth(self, sTrCode: str, nCp: int, strMonth: str) -> str: + """ + 입력된 종목코드와 동일한 행사가의 코드중 입력한 월물의 코드를 구한다. + + Args: + sTrCode (str): 종목코드 + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + strMonth (str): 월물 (6자리, YYYYMM) + + Returns: + str: 종목코드 + + Examples: + >>> GetOptionCodeByMonth("201J7260", 2, "201412") + "201JC260" + """ + ...
+ +
[docs] def GetOptionCodeByActPrice(self, sTrCode: str, nCp: int, nTick: int) -> str: + """ + 입력된 종목코드와 동일한 월물의 코드중 입력한 틱만큼 벌어진 코드를 구한다. + + Args: + sTrCode (str): 종목코드 + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + nTick (int): 행사가 틱 + + Returns: + str: 종목코드 + + Examples: + >>> GetOptionCodeByActPrice("201J7260", 2, -1) + "201J7262" + """ + ...
+ +
[docs] def GetSFutureList(self, strBaseAssetCode: str) -> str: + """ + 주식선물 코드 리스트를 반환한다. + + 출력값의 코드간 구분은 ';' 이다. + + Args: + strBaseAssetCode (str): 기초자산코드 + + Return: + str: 종목코드 리스트 + """ + ...
+ +
[docs] def GetSFutureCodeByIndex(self, strBaseAssetCode: str, nIndex: int) -> str: + """ + 주식선물 코드를 반환한다. + + Args: + strBaseAssetCode (str): 기초자산코드 + nIndex (int): 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드, 8 ~ 11: 스타 선물, 12 ~ : 스타 스프레드 + + Return: + str: 종목코드 리스트 + + Examples: + >>> GetSFutureCodeByIndex("11", 0) + """ + ...
+ +
[docs] def GetSActPriceList(self, strBaseAssetGb: str) -> str: + """ + 주식옵션 행사가 리스트를 반환한다. + + Args: + strBaseAssetGb (str): 기초자산코드구분 + + Return: + str: 행사가 리스트, 행사가간 구분은 ';' + + Examples: + >>> GetSActPriceList("11") + """ + ...
+ +
[docs] def GetSMonthList(self, strBaseAssetGb: str) -> str: + """ + 주식옵션 월물 리스트를 반환한다. + + Args: + strBaseAssetGb (str): 기초자산코드구분 + + Return: + str: 월물 리스트, 월물간 구분은 ';' + + Examples: + >>> GetSMonthList("11") + """ + ...
+ +
[docs] def GetSOptionCode( + self, strBaseAssetGb: str, strActPrice: str, nCp: int, strMonth: str + ) -> str: + """ + 주식옵션 코드를 반환한다. + + Args: + strBaseAssetGb (str): 기초자산코드구분 + strActPrice (str): 행사가 (소수점 포함) + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + strMonth (str): 월물 (6자리, YYYYMM) + + Returns: + str: 주식옵션 코드 + + Examples: + >>> GetSOptionCode("11", "1300000", 2, "1412") + """ + ...
+ +
[docs] def GetSOptionCodeByMonth( + self, strBaseAssetGb: str, sTrCode: str, nCp: int, strMonth: str + ) -> str: + """ + 입력한 주식옵션 코드에서 월물만 변경하여 반환한다. + + Args: + strBaseAssetGb (str): 기초자산코드구분 + sTrCode (str): 종목코드 + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + strMonth (str): 월물 (6자리, YYYYMM) + + Returns: + str: 주식옵션 코드 + + Examples: + >>> GetSOptionCodeByMonth("11", "211J8045", 2, "1412") + """ + ...
+ +
[docs] def GetSOptionCodeByActPrice( + self, strBaseAssetGb: str, sTrCode: str, nCp: int, nTick: int + ) -> str: + """ + 입력한 주식옵션 코드에서 행사가만 변경하여 반환한다. + + Args: + strBaseAssetGb (str): 기초자산코드구분 + sTrCode (str): 종목코드 + nCp (int): 콜/풋 구분 (2:콜, 3:풋) + nTick (int): 행사가 틱 + + Returns: + str: 주식옵션 코드 + + Examples: + >>> GetSOptionCodeByActPrice("11", "211J8045", 2, 4); + """ + ...
+ +
[docs] def GetSFOBasisAssetList(self) -> str: + """ + 주식선옵 기초자산코드/종목명을 반환한다. + + Returns: + str: 기초자산코드/종목명, 코드와 종목명 구분은 '|', 코드간 구분은 ';' + """ + ...
+ +
[docs] def GetOptionATM(self) -> str: + """ + 지수옵션 ATM을 반환한다. + + Returns: + str: ATM + """ + ...
+ +
[docs] def GetSOptionATM(self, strBaseAssetGb: str) -> str: + """ + 주식옵션 ATM을 반환한다. + + Returns: + str: ATM + """ + ...
+ +
[docs] def GetBranchCodeName(self) -> str: + """ + 회원사 코드와 이름을 반환합니다. + + Returns: + str: 회원사코드/회원사명, 코드와 이름 구분은 '|', 코드간 구분은 ';' (회원사코드|회원사명;회원사코드|회원사명;...) + """ + ...
+ +
[docs] def CommInvestRqData(self, sMarketGb: str, sRQName: str, sScreenNo: str) -> int: + """ + 지원하지 않는 함수. + + 시장 구분: + - 001: 코스피 + - 002: 코스닥 + - 003: 선물 + - 004: 콜옵션 + - 005: 풋옵션 + - 006: 스타선물 + - 007: 주식선물 + - 008: 3년국채 + - 009: 5년국채 + - 010: 10년국채 + - 011: 달러선물 + - 012: 엔선물 + - 013: 유로선물 + - 014: 미니금선물 + - 015: 금선물 + - 016: 돈육선물 + - 017: 달러콜옵션 + - 018: 달러풋옵션 + + Args: + sMarketGb (str): 시장구분 + sRQName (str): 사용자 구분값 + sScreenNo (str): 화면번호 (4자리) + + Returns: + str: 통신결과 + + Examples: + >>> CommInvestRqData("T00108;T00109", 0, 2, "RQ_1", "0101") + """ + ...
+ +
[docs] def SendOrderCredit( + self, + sRQName: str, + sScreenNo: str, + sAccNo: str, + nOrderType: int, + sCode: str, + nQty: int, + nPrice: int, + sHogaGb: str, + sCreditGb: str, + sLoanDate: str, + sOrgOrderNo: str, + ) -> int: + """ + 신용주식 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 국내주식 신용주문 전용함수입니다. 대주거래는 지원하지 않습니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 신용거래 구분: + - 03: 신용매수 주문 \\- 자기융자 + - 대출일은 공백 입력 + - 33: 신용매도 융자상환 주문 \\- 자기융자 + - 대출일은 종목별 대출일 입력 + - OPW00005/OPW00004 TR조회로 대출일 조회 + - 99: 신용매도 자기융자 합 + - 대출일은 "99991231" 입력 + - 단, 신용잔고 5개 까지만 융자합 주문 가능 + + 대출일은 YYYYMMDD 형식입니다. + 신용매도 - 자기융자 일때는 종목별 대출일을 입력하고 신용매도 - 융자합이면 "99991231"을 입력합니다. + + Args: + sRQName (str): 사용자 구분 요청명 + sScreenNo (str): 화면번호 (4자리) + sAccNo (str): 계좌번호 (10자리) + nOrderType (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + sCode (str): 종목코드 (6자리) + nQty (int): 주문수량 + nPrice (int): 주문단가 + sHogaGb (str): 거래구분 + sCreditGb (str): 신용구분 + sLoanDate (str): 대출일 (8자리, YYYYMMDD) + sOrgOrderNo (str): 원주문번호 + + Returns: + int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + """ + ...
+ +
[docs] def KOA_Functions(self, sFunctionName: str, sParam: str) -> str: + """ + OpenAPI 기본 기능 이외의 기능들을 제공하는 헬퍼 함수. + + KOA_Function() 함수는 OpenAPI 기본 기능 이외의 기능을 사용하기 쉽도록 만든 함수입니다. + 두 개의 인자값을 사용합니다. + + 기능 목록: + + 1. 계좌 비밀번호 입력창 출력 + + >>> KOA_Functions("ShowAccountWindow", "") + + 2. 접속 서버 확인 (1:모의투자, 나머지:실서버) + + >>> KOA_Functions("GetServerGubun", "") + + 3. 주식종목 시장구분, 종목분류등 정보제공 (구분자는 '|' 와 ';') + 호출결과는 입력한 종목에 대한 대분류, 중분류, 업종구분값을 구분자로 연결한 문자열입니다. + + >>> KOA_Functions("GetMasterStockInfo", "039490") + "시장구분0|거래소;시장구분1|중형주;업종구분|금융업;" + + 4. 조건검색 종목코드와 현재가 수신 (실시간 조건검색은 사용할 수 없음) + 조건검색결과에 종목코드와 그 종목의 현재가를 함께 수신하는 방법이며 실시간 조건검색에서는 사용할 수 없고 오직 조건검색에만 사용할수 있습니다. + + >>> KOA_Functions("SetConditionSearchFlag", "AddPrice") # 현재가 포함하도록 설정 + + 현재가 포함으로 설정시 OnReceiveTrCondition() 이벤트에 "종목코드1^현재가1;종목코드2^현재가2;...종목코드n^현재가n" 형식으로 전달됨. + + >>> KOA_Functions("SetConditionSearchFlag", "DelPrice") # 현재가 미포함 (원래 상태로 전환) + + 현재가 미포함시 기존처럼 "종목코드1^종목코드2...종목코드n" 형식으로 전달므로 설정에 따라 수신데이터 처리방법이 달라져야 하므로 주의하셔야 합니다. + + 5. 업종코드목록 획득 + + >>> KOA_Functions("GetUpjongCode", "0") + + 두번째 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + + 함수반환값은 "시장구분값,업종코드,업종명|시장구분값,업종코드,업종명|...|시장구분값,업종코드,업종명" 형식입니다. + 즉 하나의 업종코드는 입력한 시장구분값과 업종코드 그리고 그 업종명이 쉼표(,)로 구분되며 각 업종코드는 '|'로 구분됩니다. + + 6. 업종이름 획득 + + >>> KOA_Functions("GetUpjongNameByCode", "업종코드입력") + + 7. ETF 투자유의 종목 여부 (2020/09/17 적용) + 거래소 제도개선으로 ETF/ETN 종목 중 투자유의 종목을 매수주문하는 경우 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. + (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) + 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. + + >>> KOA_Functions("IsOrderWarningETF", "종목코드(6자리)") + + 투자유의 종목인 경우 "1" 값이 리턴, 그렇지 않은 경우 "0" 값 리턴. (ETF가 아닌 종목을 입력시 "0" 값 리턴.) + + 8. 주식 전종목대상 투자유의 종목 여부 (2020/11/26 적용) + 거래소 제도개선으로 주식 종목 중 정리매매/단기과열/투자위험/투자경고 종목을 매수주문하는 경우 + 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) + 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. + + >>> KOA_Functions("IsOrderWarningStock", "종목코드(6자리)") + + 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 + + 9. 상장주식수 구하기 (2021/04/08 적용) + 상장주식수를 구하는 GetMasterListedStockCnt() 기존 함수 사용시 특정 종목 데이터가 long 형을 Overflow 하는 현상이 있습니다. + 이에, 상장주식수를 구하는 기능을 신규 추가 합니다. 사용법은 아래와 같습니다. + + >>> KOA_Functions("GetMasterListedStockCntEx", "종목코드(6자리)") + + Args: + sFunctionName (str): 함수이름 혹은 기능이름 + sParam (str): 함수 매개변수 + + Returns: + str: 결과 데이터 + """ + ...
+ +
[docs] def SetInfoData(self, sInfoData: str) -> int: + """ + 다수의 아이디로 자동로그인이 필요할 때 사용한다. + + Args: + sInfoData (str): 아이디 + + Returns: + int: 통신결과 + + Examples: + >>> SetInfoData("UserID") + """ + ...
+ +
[docs] def SetRealReg( + self, strScreenNo: str, strCodeList: str, strFidList: str, strOptType: str + ) -> int: + """ + 실시간 등록을 한다. + + 종목코드와 FID 리스트를 이용해서 실시간 시세를 등록하는 함수입니다. + 한번에 등록가능한 종목과 FID갯수는 100종목, 100개 입니다. + 실시간 등록타입을 0으로 설정하면 등록한 종목들은 실시간 해지되고 등록한 종목만 실시간 시세가 등록됩니다. + 실시간 등록타입을 1로 설정하면 먼저 등록한 종목들과 함께 실시간 시세가 등록됩니다 + + strOptType 이 "0" 으로 하면 같은 화면에서 다른 종목 코드로 실시간 등록을 하게 되면 + 마지막에 사용한 종목코드만 실시간 등록이 되고 기존에 있던 종목은 실시간이 자동 해지됨. + "1" 로 하면 같은 화면에서 다른 종목들을 추가하게 되면 기존에 등록한 종목도 함께 실시간 시세를 받을 수 있음. + 꼭 같은 화면이여야 하고 최초 실시간 등록은 "0" 으로 하고 이후부터 "1" 로 등록해야함. + + Args: + strScreenNo (str): 화면번호 (4자리) + strCodeList (str): 종목코드 (복수종목가능, ';' 구분자) + strFidList (str): FID (';' 구분자) + strOptType (str): 등록타입 (0:최초 등록시, 혹은 기존 등록된 종목 해지하고 등록 1:기존 등록된 종목 유지하고 등록) + + Returns: + int: 통신결과 + """ + ...
+ +
[docs] def GetConditionLoad(self) -> int: + """ + 서버에 저장된 사용자 조건식을 조회해서 임시로 파일에 저장. + + 서버에 저장된 사용자 조건검색 목록을 요청합니다. + 조건검색 목록을 모두 수신하면 OnReceiveConditionVer() 이벤트가 발생됩니다. + 조건검색 목록 요청을 성공하면 1, 아니면 0을 리턴합니다. + + System 폴더에 아이디_NewSaveIndex.dat 파일로 저장된다. OCX 가 종료되면 삭제시킨다. + 조건검색 사용시 이 함수를 최소 한번은 호출해야 조건검색을 할 수 있다. + 영웅문에서 사용자 조건을 수정 및 추가하였을 경우에도 최신의 사용자 조건을 받고 싶으면 다시 + 조회해야한다. + + Returns: + int: 성공하면 1, 아니면 0을 반환 + """ + ...
+ +
[docs] def GetConditionNameList(self) -> str: + """ + 조건검색 조건명 리스트를 받아온다. + + 서버에서 수신한 사용자 조건식을 조건식의 고유번호와 조건식 이름을 한 쌍으로 하는 문자열들로 전달합니다. + 조건식 하나는 조건식의 고유번호와 조건식 이름이 구분자 '^' 로 나뉘어져 있으며 각 조건식은 ';' 로 나뉘어져 있습니다. + 이 함수는 OnReceiveConditionVer() 이벤트에서 사용해야 합니다. + + Returns: + str: 조건명 리스트 문자열 + + Examples: + >>> GetConditionNameList() + "1^내조건식1;2^내조건식2;5^내조건식3;..." + """ + ...
+ +
[docs] def SendCondition( + self, strScrNo: str, strConditionName: str, nIndex: int, nSearch: int + ) -> int: + """ + 조건검색 종목조회TR을 송신한다. + + 서버에 조건검색을 요청하는 함수입니다. + 마지막 인자값으로 조건검색만 할것인지 실시간 조건검색도 수신할 것인지를 지정할 수 있습니다. + GetConditionNameList() 함수로 얻은 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. + 리턴값 1이면 성공이며, 0이면 실패입니다. + 요청한 조건식이 없거나 조건 고유번호와 조건명이 서로 안맞거나 조회횟수를 초과하는 경우 실패하게 됩니다. + + 단순 조건식에 맞는 종목을 조회하기 위해서는 조회구분을 0으로 하고, + 실시간 조건검색을 하기 위해서는 조회구분을 1로 한다. + OnReceiveTrCondition() 으로 결과값이 온다. + 연속조회가 필요한 경우에는 응답받는 곳에서 연속조회 여부에 따라 연속조회를 송신하면된다. + + Args: + strScrNo (str): 화면번호 + strConditionName (str): 조건식 이름 + nIndex (int): 조건식 인덱스 + nSearch (int): 조회구분 (0:일반조회, 1:실시간조회 (최초 일반조회 + 이후 실시간조회), 2:연속조회) + + Returns: + int: 성공하면 1, 아니면 0을 반환 + """ + ...
+ +
[docs] def SendConditionStop( + self, strScrNo: str, strConditionName: str, nIndex: int + ) -> None: + """ + 조건검색 실시간 중지TR을 송신한다. + + 실시간 조건검색을 중지할 때 사용하는 함수입니다. + 조건식 조회할때 얻는 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. + + 해당 조건명의 실시간 조건검색을 중지하거나, + 다른 조건명으로 바꿀 때 이전 조건명으로 실시간 조건검색을 반드시 중지해야한다. + 화면 종료시에도 실시간 조건검색을 한 조건명으로 전부 중지해줘야 한다. + + Args: + strScrNo (str): 화면번호 + strConditionName (str): 조건식 이름 + nIndex (int): 조건식 인덱스 + + Returns: + None + """ + ...
+ +
[docs] def GetCommDataEx(self, strTrCode: str, strRecordName: str): + """ + 차트 조회 데이터를 배열로 받아온다. + + 조회 수신데이터 크기가 큰 차트데이터를 한번에 가져올 목적으로 만든 차트조회 전용함수입니다. + + 조회 데이터가 많은 차트 경우 GetCommData()로 항목당 하나씩 받아오는 것 보다 + 한번에 데이터 전부를 받아서 사용자가 처리할 수 있도록 배열로 받는다. + + ※ Qt 기준으로 QVariant 타입의 배열을 반환하지만 PySide2 에서는 완전히 똑같이 지원하진 않습니다. + + Args: + strTrCode (str): TR코드 + strRecordName (str): 레코드명 + + Returns: + QVariant: 조회 데이터 배열 + """ + ...
+ +
[docs] def SetRealRemove(self, strScrNo: str, strDelCode: str) -> None: + """ + 종목별 실시간 해제. + + 실시간시세 해지 함수이며 화면번호와 종목코드를 이용해서 상세하게 설정할 수 있습니다. + + ※ A종목에 대한 실시간이 여러 화면번호로 중복 등록되어 있는 경우 특정 화면번호를 이용한 + SetRealRemove() 함수호출시 A종목의 실시간시세는 해지되지 않습니다. + + SetRealReg() 함수로 실시간 등록한 종목만 실시간 해제 할 수 있다. + + Args: + strScrNo (str): 화면번호 (4자리) 또는 "ALL" + strDelCode (str): 종목코드 또는 "ALL" + + Returns: + None + """ + ...
+ +
[docs] def GetMarketType(self, sTrCode: str) -> int: + """ + 주어진 종목코드의 시장구분값을 가져온다. + + 시장 구분: + - 0: 장내 + - 3: ELW + - 4: 뮤추얼펀드 + - 5: 신주인수권 + - 6: 리츠 + - 8: ETF + - 9: 하이일드펀드 + - 10: 코스닥 + - 30: K-OTC + - 50: 코넥스 (KONEX) + + Args: + sTrCode (str): 종목코드 + + Returns: + int: 시장 구분값 + """ + ...
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.html new file mode 100644 index 00000000..b10d4b71 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.html @@ -0,0 +1,208 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature

+from __future__ import annotations
+
+from typing import Dict, List
+
+import pythoncom
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import (
+    KiwoomOpenApiPlusDispatchFunctions,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature import (
+    KiwoomOpenApiPlusSignature,
+)
+from koapy.utils.builtin import dir_public
+
+
+
[docs]class KiwoomOpenApiPlusDispatchSignature(KiwoomOpenApiPlusSignature): + +
[docs] DISPATCH_SIGNATURES_BY_NAME: Dict[str, KiwoomOpenApiPlusDispatchSignature] = {}
+ + @classmethod +
[docs] def from_name(cls, name: str) -> KiwoomOpenApiPlusDispatchSignature: + signature = cls.DISPATCH_SIGNATURES_BY_NAME[name] + return signature
+ + @classmethod +
[docs] def names(cls) -> List[str]: + names = cls.DISPATCH_SIGNATURES_BY_NAME.keys() + names = list(names) + if not names: + _names = dir_public(KiwoomOpenApiPlusDispatchFunctions) + return names
+ + @classmethod + def _make_dispatch_signatures_by_name( + cls, + ) -> Dict[str, KiwoomOpenApiPlusDispatchSignature]: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( + DISPATCH_OLE_ITEM, + ) + + dispatch = DISPATCH_OLE_ITEM + dispatch_signatures_by_name: Dict[str, KiwoomOpenApiPlusDispatchSignature] = {} + if dispatch: + dispatch_funcs = [ + (name, entry) + for name, entry in dispatch.mapFuncs.items() + if not any( + [ + entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED + and entry.desc[0] != pythoncom.DISPID_NEWENUM, + entry.desc[3] != pythoncom.FUNC_DISPATCH, + entry.desc[0] == pythoncom.DISPID_NEWENUM, + ] + ) + ] + for func_name, entry in dispatch_funcs: + signature = cls._from_entry(func_name, entry) + dispatch_signatures_by_name[func_name] = signature + return dispatch_signatures_by_name + + @classmethod + def _initialize(cls): + cls.DISPATCH_SIGNATURES_BY_NAME = cls._make_dispatch_signatures_by_name()
+ + +KiwoomOpenApiPlusDispatchSignature._initialize() # pylint: disable=protected-access +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.html new file mode 100644 index 00000000..7f3b5dea --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.html @@ -0,0 +1,273 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable

+from __future__ import annotations
+
+from concurrent.futures import Future
+from inspect import Signature
+from typing import Any, Callable, Generic, List, Optional, Sequence, TypeVar
+
+try:
+    from typing import ParamSpec
+except ImportError:
+    from typing_extensions import ParamSpec
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import (
+    KiwoomOpenApiPlusDispatchSignature,
+)
+from koapy.compat.pyside2.QtAxContainer import QAxWidget
+from koapy.compat.pyside2.QtCore import QObject, Qt, Signal
+
+
[docs]P = ParamSpec("P")
+
[docs]R = TypeVar("R")
+ + +
[docs]class KiwoomOpenApiPlusDynamicCallableRunnable: + def __init__( + self, + future: Future, + fn: Callable[..., Any], + args: Sequence[Any], + ): + self._future = future + self._fn = fn + self._args = args + +
[docs] def run(self): + if not self._future.set_running_or_notify_cancel(): + return + try: + result = self._fn(self._args) + except BaseException as exc: # pylint: disable=broad-except + self._future.set_exception(exc) + # break a reference cycle with the exception 'exc' + self = None # pylint: disable=self-cls-assignment + else: + self._future.set_result(result)
+ +
[docs] def cancel(self): + return self._future.cancel()
+ + +
[docs]class KiwoomOpenApiPlusDynamicCallable(QObject, Generic[P, R]): + +
[docs] ready_runnable = Signal(KiwoomOpenApiPlusDynamicCallableRunnable)
+ + def __init__( + self, + control: QAxWidget, + name: str, + parent: Optional[QObject] = None, + ): + super().__init__(parent) + + self._control = control + self._name = name + + self._signature = KiwoomOpenApiPlusDispatchSignature.from_name(self._name) + self._function = self._signature.to_pyside2_function_prototype() + self._has_return_value = ( + self._signature.return_annotation is not Signature.empty + ) + + self.ready_runnable.connect(self.on_ready_runnable, Qt.QueuedConnection) + + self.__name__ = self._name + self.__signature__ = self._signature + +
[docs] def bind_dynamic_call_args(self, *args, **kwargs) -> List[Any]: + try: + ba = self._signature.bind(*args, **kwargs) + except TypeError as e: + raise TypeError( + "Exception while binding arguments for function: %s" % self._name + ) from e + ba.apply_defaults() + args = list(ba.args) + return args
+ +
[docs] def is_valid_return_type(self, result: Any) -> bool: + is_valid = True + if self._has_return_value: + if not isinstance(result, self._signature.return_annotation): + is_valid = False + return is_valid
+ +
[docs] def check_return_value(self, result: Any): + if not self.is_valid_return_type(result): + raise TypeError( + "Return type of %s was expected for function call %s(...), but %s was found" + % ( + self._signature.return_annotation, + self._name, + type(result), + ) + ) + return result
+ +
[docs] def dynamic_call(self, args: Sequence[Any]) -> R: + return self._control.dynamicCall(self._function, args)
+ +
[docs] def dynamic_call_and_check(self, args: Sequence[Any]) -> R: + result = self.dynamic_call(args) + self.check_return_value(result) + return result
+ +
[docs] def call(self, *args: P.args, **kwargs: P.kwargs) -> R: + args = self.bind_dynamic_call_args(*args, **kwargs) + result = self.dynamic_call_and_check(args) + return result
+ +
[docs] def async_call(self, *args: P.args, **kwargs: P.kwargs) -> Future: + args = self.bind_dynamic_call_args(*args, **kwargs) + future = Future() + runnable = KiwoomOpenApiPlusDynamicCallableRunnable( + future, self.dynamic_call_and_check, args + ) + self.ready_runnable.emit(runnable) + return future
+ +
[docs] def on_ready_runnable(self, runnable: KiwoomOpenApiPlusDynamicCallableRunnable): + runnable.run()
+ + def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: + return self.call(*args, **kwargs)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.html new file mode 100644 index 00000000..1380d06e --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.html @@ -0,0 +1,240 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint

+import threading
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin import (
+    KiwoomOpenApiPlusEntrypointMixin,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import (
+    KiwoomOpenApiPlusServiceClient,
+)
+from koapy.config import config, get_32bit_executable
+from koapy.utils.logging import get_verbosity
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.networking import get_free_localhost_port
+from koapy.utils.subprocess import Popen
+
+
+
[docs]class KiwoomOpenApiPlusEntrypoint(KiwoomOpenApiPlusEntrypointMixin, Logging): + def __init__( + self, + port=None, + client_check_timeout=None, + ): + if port is None: + port = ( + config.get("koapy.backend.kiwoom_open_api_plus.grpc.port", 0) + or get_free_localhost_port() + ) + + self._port = port + self._client_check_timeout = client_check_timeout + + self._server_executable = get_32bit_executable() + self._server_proc_args = [self._server_executable, "-m", "koapy.cli", "serve"] + if self._port is not None: + self._server_proc_args.extend(["-p", str(self._port)]) + + self._verbosity = get_verbosity() + self._server_proc_args.extend(["-" + "v" * self._verbosity]) + + self._server_proc = None + self._server_proc_start_timeout = 30 + self._server_proc_terminate_timeout = 30 + + self._client = KiwoomOpenApiPlusServiceClient(port=self._port) + + self.logger.debug("Testing if client is ready...") + if not self._client.is_ready(self._client_check_timeout): + self.logger.debug("Client is not ready") + self.logger.debug("Creating a new server...") + self._server_proc = Popen(self._server_proc_args) + assert self._client.is_ready( + self._server_proc_start_timeout + ), "Failed to create server" + self._stub = self._client.get_stub() + else: + self.logger.debug("Client is ready, using existing server") + self._stub = self._client.get_stub() + + self._context_lock = threading.RLock() + self._enter_count = 0 + + def __del__(self): + self.close() + + def __enter__(self): + with self._context_lock: + self._enter_count += 1 + return self + + def __exit__(self, exc_type, exc_value, traceback): + with self._context_lock: + if self._enter_count > 0: + self._enter_count -= 1 + if self._enter_count == 0: + self.close() + +
[docs] def get_stub(self): + return self._stub
+ +
[docs] def close_client(self): + self._client.close()
+ +
[docs] def close_server_proc(self): + if self._server_proc is not None: + self._server_proc.terminate() # maybe soft termination available via grpc? rather than hard termination + self._server_proc.wait(self._server_proc_terminate_timeout) + self._server_proc = None
+ +
[docs] def close(self): + self.close_client() + self.close_server_proc()
+ + def __getattr__(self, name): + try: + stub = self.__getattribute__("_stub") + except AttributeError: + return self.__getattribute__(name) + else: + return getattr(stub, name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.html new file mode 100644 index 00000000..7df5072f --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.html @@ -0,0 +1,144 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin

+
[docs]class KiwoomOpenApiPlusEntrypointMixin: + pass
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.html new file mode 100644 index 00000000..5875398a --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.html @@ -0,0 +1,489 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError

+from concurrent.futures import Future
+from functools import wraps
+from typing import Callable, Optional, TypeVar, Union
+
+
[docs]CallableReturnsInt = Callable[..., int]
+ +
[docs]IntOrBool = TypeVar( + "IntOrBool", + int, + bool, +)
+ +
[docs]CallableReturnsIntOrBool = TypeVar( + "CallableReturnsIntOrBool", + Callable[..., int], + Callable[..., bool], +)
+ +
[docs]IntCompatible = TypeVar( + "IntCompatible", + int, + Callable[..., int], + Future, +)
+ +
[docs]BoolCompatible = TypeVar( + "BoolCompatible", + int, + bool, + Callable[..., int], + Callable[..., bool], + Future, +)
+ + +
[docs]class KiwoomOpenApiPlusError(Exception): + def __init__(self, message: Optional[str] = None): + if message is not None: + super().__init__(message) + else: + super().__init__() + + self._message = message + + @property +
[docs] def message(self): + return self._message
+ + @classmethod +
[docs] def try_or_raise( + cls, + arg: IntCompatible, + message: Optional[str] = None, + except_callback: Optional[Callable] = None, + ) -> IntCompatible: + return KiwoomOpenApiPlusNegativeReturnCodeError.try_or_raise( + arg, message, except_callback + )
+ + @classmethod +
[docs] def try_or_raise_boolean( + cls, + arg: BoolCompatible, + message: str, + except_callback: Optional[Callable] = None, + ) -> BoolCompatible: + return KiwoomOpenApiPlusBooleanReturnCodeError.try_or_raise( + arg, message, except_callback + )
+ + @classmethod +
[docs] def get_error_message_by_code(cls, code: int, default: Optional[str] = None): + return KiwoomOpenApiPlusNegativeReturnCodeError.get_error_message_by_code( + code, default + )
+ + +
[docs]class KiwoomOpenApiPlusNegativeReturnCodeError(KiwoomOpenApiPlusError): + +
[docs] OP_ERR_NONE = 0
+
[docs] OP_ERR_FAIL = -10
+
[docs] OP_ERR_COND_NOTFOUND = -11
+
[docs] OP_ERR_COND_MISMATCH = -12
+
[docs] OP_ERR_COND_OVERFLOW = -13
+
[docs] OP_ERR_TR_FAIL = -22
+
[docs] OP_ERR_LOGIN = -100
+
[docs] OP_ERR_CONNECT = -101
+
[docs] OP_ERR_VERSION = -102
+
[docs] OP_ERR_FIREWALL = -103
+
[docs] OP_ERR_MEMORY = -104
+
[docs] OP_ERR_INPUT = -105
+
[docs] OP_ERR_SOCKET_CLOSED = -106
+
[docs] OP_ERR_SISE_OVERFLOW = -200
+
[docs] OP_ERR_RQ_STRUCT_FAIL = -201
+
[docs] OP_ERR_RQ_STRING_FAIL = -202
+
[docs] OP_ERR_NO_DATA = -203
+
[docs] OP_ERR_OVER_MAX_DATA = -204
+
[docs] OP_ERR_DATA_RCV_FAIL = -205
+
[docs] OP_ERR_OVER_MAX_FID = -206
+
[docs] OP_ERR_REAL_CANCEL = -207
+
[docs] OP_ERR_ORD_WRONG_INPUT = -300
+
[docs] OP_ERR_ORD_WRONG_ACCTNO = -301
+
[docs] OP_ERR_OTHER_ACC_USE = -302
+
[docs] OP_ERR_MIS_2BILL_EXC = -303
+
[docs] OP_ERR_MIS_5BILL_EXC = -304
+
[docs] OP_ERR_MIS_1PER_EXC = -305
+
[docs] OP_ERR_MIS_3PER_EXC = -306
+
[docs] OP_ERR_SEND_FAIL = -307
+
[docs] OP_ERR_ORD_OVERFLOW = -308
+
[docs] OP_ERR_ORD_OVERFLOW2 = -311
+
[docs] OP_ERR_MIS_300CNT_EXC = -309
+
[docs] OP_ERR_MIS_500CNT_EXC = -310
+
[docs] OP_ERR_ORD_WRONG_ACCTINFO = -340
+
[docs] OP_ERR_ORD_SYMCODE_EMPTY = -500
+ +
[docs] MSG_ERR_NONE = "정상처리"
+
[docs] MSG_ERR_FAIL = "실패"
+
[docs] MSG_ERR_COND_NOTFOUND = "조건번호 없음"
+
[docs] MSG_ERR_COND_MISMATCH = "조건번호와 조건식 틀림"
+
[docs] MSG_ERR_COND_OVERFLOW = "조건검색 조회요청 초과"
+
[docs] MSG_ERR_TR_FAIL = "전문 처리 실패"
+
[docs] MSG_ERR_LOGIN = "사용자정보 교환 실패"
+
[docs] MSG_ERR_CONNECT = "서버접속 실패"
+
[docs] MSG_ERR_VERSION = "버전처리 실패"
+
[docs] MSG_ERR_FIREWALL = "개인방화벽 실패"
+
[docs] MSG_ERR_MEMORY = "메모리보호 실패"
+
[docs] MSG_ERR_INPUT = "함수입력값 오류"
+
[docs] MSG_ERR_SOCKET_CLOSED = "통신 연결종료"
+
[docs] MSG_ERR_SISE_OVERFLOW = "시세조회 과부하"
+
[docs] MSG_ERR_RQ_STRUCT_FAIL = "전문작성 초기화 실패"
+
[docs] MSG_ERR_RQ_STRING_FAIL = "전문작성 입력값 오류"
+
[docs] MSG_ERR_NO_DATA = "데이터 없음"
+
[docs] MSG_ERR_OVER_MAX_DATA = "조회 가능한 종목수 초과"
+
[docs] MSG_ERR_DATA_RCV_FAIL = "데이터수신 실패"
+
[docs] MSG_ERR_OVER_MAX_FID = "조회 가능한 FID수 초과"
+
[docs] MSG_ERR_REAL_CANCEL = "실시간 해제 오류"
+
[docs] MSG_ERR_ORD_WRONG_INPUT = "입력값 오류"
+
[docs] MSG_ERR_ORD_WRONG_ACCTNO = "계좌 비밀번호 없음"
+
[docs] MSG_ERR_OTHER_ACC_USE = "타인계좌사용 오류"
+
[docs] MSG_ERR_MIS_2BILL_EXC = "주문가격이 20억원을 초과"
+
[docs] MSG_ERR_MIS_5BILL_EXC = "주문가격이 50억원을 초과"
+
[docs] MSG_ERR_MIS_1PER_EXC = "주문수량이 총발행주수의 1%초과오류"
+
[docs] MSG_ERR_MIS_3PER_EXC = "주문수량이 총발행주수의 3%초과오류"
+
[docs] MSG_ERR_SEND_FAIL = "주문전송 실패"
+
[docs] MSG_ERR_ORD_OVERFLOW = "주문전송 과부하"
+
[docs] MSG_ERR_ORD_OVERFLOW2 = "주문전송 과부하"
+
[docs] MSG_ERR_MIS_300CNT_EXC = "주문수량 300계약 초과"
+
[docs] MSG_ERR_MIS_500CNT_EXC = "주문수량 500계약 초과"
+
[docs] MSG_ERR_ORD_WRONG_ACCTINFO = "계좌정보없음"
+
[docs] MSG_ERR_ORD_SYMCODE_EMPTY = "종목코드없음"
+ +
[docs] ERROR_MESSAGE_BY_CODE = { + OP_ERR_NONE: MSG_ERR_NONE, + OP_ERR_FAIL: MSG_ERR_FAIL, + OP_ERR_COND_NOTFOUND: MSG_ERR_COND_NOTFOUND, + OP_ERR_COND_MISMATCH: MSG_ERR_COND_MISMATCH, + OP_ERR_COND_OVERFLOW: MSG_ERR_COND_OVERFLOW, + OP_ERR_TR_FAIL: MSG_ERR_TR_FAIL, + OP_ERR_LOGIN: MSG_ERR_LOGIN, + OP_ERR_CONNECT: MSG_ERR_CONNECT, + OP_ERR_VERSION: MSG_ERR_VERSION, + OP_ERR_FIREWALL: MSG_ERR_FIREWALL, + OP_ERR_MEMORY: MSG_ERR_MEMORY, + OP_ERR_INPUT: MSG_ERR_INPUT, + OP_ERR_SOCKET_CLOSED: MSG_ERR_SOCKET_CLOSED, + OP_ERR_SISE_OVERFLOW: MSG_ERR_SISE_OVERFLOW, + OP_ERR_RQ_STRUCT_FAIL: MSG_ERR_RQ_STRUCT_FAIL, + OP_ERR_RQ_STRING_FAIL: MSG_ERR_RQ_STRING_FAIL, + OP_ERR_NO_DATA: MSG_ERR_NO_DATA, + OP_ERR_OVER_MAX_DATA: MSG_ERR_OVER_MAX_DATA, + OP_ERR_DATA_RCV_FAIL: MSG_ERR_DATA_RCV_FAIL, + OP_ERR_OVER_MAX_FID: MSG_ERR_OVER_MAX_FID, + OP_ERR_REAL_CANCEL: MSG_ERR_REAL_CANCEL, + OP_ERR_ORD_WRONG_INPUT: MSG_ERR_ORD_WRONG_INPUT, + OP_ERR_ORD_WRONG_ACCTNO: MSG_ERR_ORD_WRONG_ACCTNO, + OP_ERR_OTHER_ACC_USE: MSG_ERR_OTHER_ACC_USE, + OP_ERR_MIS_2BILL_EXC: MSG_ERR_MIS_2BILL_EXC, + OP_ERR_MIS_5BILL_EXC: MSG_ERR_MIS_5BILL_EXC, + OP_ERR_MIS_1PER_EXC: MSG_ERR_MIS_1PER_EXC, + OP_ERR_MIS_3PER_EXC: MSG_ERR_MIS_3PER_EXC, + OP_ERR_SEND_FAIL: MSG_ERR_SEND_FAIL, + OP_ERR_ORD_OVERFLOW: MSG_ERR_ORD_OVERFLOW, + OP_ERR_ORD_OVERFLOW2: MSG_ERR_ORD_OVERFLOW2, + OP_ERR_MIS_300CNT_EXC: MSG_ERR_MIS_300CNT_EXC, + OP_ERR_MIS_500CNT_EXC: MSG_ERR_MIS_500CNT_EXC, + OP_ERR_ORD_WRONG_ACCTINFO: MSG_ERR_ORD_WRONG_ACCTINFO, + OP_ERR_ORD_SYMCODE_EMPTY: MSG_ERR_ORD_SYMCODE_EMPTY, + }
+ + @classmethod +
[docs] def get_error_message_by_code(cls, code: int, default: Optional[str] = None): + return cls.ERROR_MESSAGE_BY_CODE.get(code, default)
+ + @classmethod +
[docs] def check_code_or_raise(cls, code: int): + if code < 0: + raise cls(code) + return code
+ + @classmethod +
[docs] def wrap_to_check_code_or_raise( + cls, func: CallableReturnsInt + ) -> CallableReturnsInt: + @wraps(func) + def wrapper(*args, **kwargs): + return cls.check_code_or_raise(func(*args, **kwargs)) + + return wrapper
+ + @classmethod +
[docs] def try_or_raise( + cls, + arg: IntCompatible, + message: Optional[str] = None, + except_callback: Optional[Callable] = None, + ) -> IntCompatible: + if isinstance(arg, Future): + + def callback(future): + exc = future.exception() + if exc: + if except_callback: + except_callback(exc) + else: + raise exc + result = future.result() + try: + cls.try_or_raise(result, message) + except cls as e: + if except_callback: + except_callback(e) + else: + raise + + arg.add_done_callback(callback) + return arg + elif isinstance(arg, int): + return cls.check_code_or_raise(arg) + elif callable(arg): + return cls.wrap_to_check_code_or_raise(arg) + else: + raise TypeError( + "Expected 'int', 'callable' or 'Future' but %s found" % type(arg) + )
+ + def __init__(self, code: int, message: Optional[str] = None): + if message is None: + message = self.get_error_message_by_code(code) + + super().__init__(message) + + self._code = code + self._message = message + + def __str__(self): + return self._message + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._code, self._message + ) + + @property +
[docs] def code(self): + return self._code
+ + +
[docs]class KiwoomOpenApiPlusBooleanReturnCodeError(KiwoomOpenApiPlusError): + +
[docs] OP_ERR_SUCCESS = 1
+
[docs] OP_ERR_FAILURE = 0
+ + @classmethod +
[docs] def check_code_or_raise( + cls, code: IntOrBool, message: Optional[str] = None + ) -> IntOrBool: + if not code: + raise cls(code, message) + return code
+ + @classmethod +
[docs] def wrap_to_check_code_or_raise( + cls, func: CallableReturnsIntOrBool, message: Optional[str] = None + ) -> CallableReturnsIntOrBool: + @wraps(func) + def wrapper(*args, **kwargs): + return cls.check_code_or_raise(func(*args, **kwargs), message) + + return wrapper
+ + @classmethod +
[docs] def try_or_raise( + cls, + arg: BoolCompatible, + message: Optional[str] = None, + except_callback: Optional[Callable] = None, + ) -> BoolCompatible: + if isinstance(arg, Future): + + def callback(future): + exc = future.exception() + if exc: + if except_callback: + except_callback(exc) + else: + raise exc + result = future.result() + try: + cls.try_or_raise(result, message) + except cls as e: + if except_callback: + except_callback(e) + else: + raise + + arg.add_done_callback(callback) + return arg + elif isinstance(arg, (int, bool)): + return cls.check_code_or_raise(arg, message) + elif callable(arg): + return cls.wrap_to_check_code_or_raise(arg, message) + else: + raise TypeError( + "Expected 'int', 'bool', 'callable' or 'Future' but %s found" + % type(arg) + )
+ + def __init__(self, code: Union[int, bool], message: Optional[str] = None): + super().__init__(message) + + self._code = code + self._message = message + + def __str__(self): + if self._message: + return self._message + else: + return self.__repr__() + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._code, self._message + ) + + @property +
[docs] def code(self): + return self._code
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.html new file mode 100644 index 00000000..5dad2d91 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.html @@ -0,0 +1,330 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions

+
[docs]class KiwoomOpenApiPlusEventFunctions: +
[docs] def OnReceiveTrData( + self, + sScrNo: str, + sRQName: str, + sTrCode: str, + sRecordName: str, + sPrevNext: str, + nDataLength: int, + sErrorCode: str, + sMessage: str, + sSplmMsg: str, + ) -> None: + """ + 서버통신 후 데이터를 받은 시점을 알려준다. + + 요청했던 조회데이터를 수신했을때 발생됩니다. + 수신된 데이터는 이 이벤트내부에서 GetCommData() 함수를 이용해서 얻어올 수 있습니다. + + 파라미터 매핑: + - sRQName = CommRqData() 의 sRQName과 매핑되는 이름이다. + - sTrCode = CommRqData() 의 sTrCode과 매핑되는 이름이다. + + Args: + sScrNo (str): 화면번호 + sRQName (str): 사용자 구분명 + sTrCode (str): TR 코드 + sRecordName (str): 레코드 명 + sPrevNext (str): 연속조회 유무 (0:추가조회 데이터 없음, 2:추가조회 데이터 있음) + nDataLength (str): 사용안함 + sErrorCode (str): 사용안함 + sMessage (str): 사용안함 + sSplmMsg (str): 사용안함 + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveRealData(self, sRealKey: str, sRealType: str, sRealData: str) -> None: + """ + 실시간데이터를 받은 시점을 알려준다. + + 실시간시세 데이터가 수신될때마다 종목단위로 발생됩니다. + SetRealReg() 함수로 등록한 실시간 데이터도 이 이벤트로 전달됩니다. + GetCommRealData() 함수를 이용해서 수신된 데이터를 얻을수 있습니다. + + Args: + sRealKey (str): 종목코드 + sRealType (str): 실시간 타입 + sRealData (str): 실시간 데이터전문 (사용불가) + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveMsg(self, sScrNo: str, sRQName: str, sTrCode: str, sMsg: str) -> None: + """ + 서버통신 후 메시지를 받은 시점을 알려준다. + + 주문전송 또는 데이터 조회요청 후 서버 메시지가 수신됩니다. + ※ 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다. + + 파라미터 매핑: + - sScrNo = CommRqData() 의 sScrNo와 매핑된다. + - sRQName = CommRqData() 의 sRQName 와 매핑된다. + - sTrCode = CommRqData() 의 sTrCode 와 매핑된다. + + 메시지 예시: + - "조회가 완료되었습니다." + - "증거금 부족으로 주문이 거부되었습니다." + - "정정할 원주문 내역이 없습니다." + - "비밀번호 입력을 확인해주시기 바랍니다." + + Args: + sScrNo: str, sRQName: str, sTrCode: str, sMsg: str + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveChejanData(self, sGubun: str, nItemCnt: int, sFIdList: str) -> None: + """ + 체결데이터를 받은 시점을 알려준다. + + 주문전송 후 주문접수, 체결통보, 잔고통보를 수신할 때 마다 발생됩니다. + GetChejanData() 함수를 이용해서 FID 항목별 값을 얻을수 있습니다. + + Args: + sGubun (str): 체결구분 (0:주문체결통보, 1:국내주식 잔고통보, 4:파생상품 잔고통보) + nItemCnt (int): 아이템 개수 + sFIdList (str): 데이터 리스트 (';' 구분자) + + Returns: + None + """ + ...
+ +
[docs] def OnEventConnect(self, nErrCode: int) -> None: + """ + 서버 접속 관련 이벤트. + + 로그인 처리 이벤트입니다. 성공이면 인자값 nErrCode가 0이며 에러는 다음과 같은 값이 전달됩니다. + + 에러코드 구분: + - OP_ERR_LOGIN(-100): 사용자 정보교환 실패 + - OP_ERR_CONNECT(-101): 서버접속 실패 + - OP_ERR_VERSION(-102): 버전처리 실패 + + Args: + nErrCode (int): 에러코드 (0:로그인 성공, 음수:실패) + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveInvestRealData(self, sRealKey: str) -> None: + """ + 더 이상 지원하지 않는 함수. + """ + ...
+ +
[docs] def OnReceiveRealCondition( + self, sTrCode: str, strType: str, strConditionName: str, strConditionIndex: str + ) -> None: + """ + 조건검색 실시간 편입,이탈 종목을 받을 시점을 알려준다. + + 실시간 조건검색 요청으로 신규종목이 편입되거나 기존 종목이 이탈될때 마다 발생됩니다. + ※ 편입되었다가 순간적으로 다시 이탈되는 종목에대한 신호는 조건검색 서버마다 차이가 발생할 수 있습니다. + + strConditionName 에 해당하는 종목이 실시간으로 들어옴. + strType 으로 편입된 종목인지 이탈된 종목인지 구분한다. + + Args: + sTrCode (str): 종목코드 + strType (str): 편입/이탈 구분 (I:편입, D:이탈) + strConditionName (str): 조건식 이름 + strConditionIndex (str): 조건식 인덱스 + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveTrCondition( + self, + sScrNo: str, + strCodeList: str, + strConditionName: str, + nIndex: int, + nNext: int, + ) -> None: + """ + 조건검색 조회응답으로 종목리스트를 받는 시점. + + 조건검색 요청에대한 서버 응답 수신시 발생하는 이벤트입니다. + 종목코드 리스트는 각 종목코드가 ';' 로 구분되서 전달됩니다. + + Args: + sScrNo (str): 화면번호 + strCodeList (str): 종목리스트 (';' 구분자) + strConditionName (str): 조건식 이름 + nIndex (int): 조건식 인덱스 + nNext (int): 연속조회 여부 (2:연속조회, 0:연속조회 없음) + + Returns: + None + """ + ...
+ +
[docs] def OnReceiveConditionVer(self, lRet: int, sMsg: str) -> None: + """ + 로컬에 사용자 조건식 저장 성공 여부를 확인하는 시점. + + 저장된 사용자 조건식 불러오기 요청에 대한 응답 수신시 발생되는 이벤트입니다. + + Args: + lRet (int): 사용자 조건식 저장 성공여부 (1:성공, 나머지:실패) + sMsg (str): 호출결과 메시지 + + Returns: + None + """ + ...
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.html new file mode 100644 index 00000000..dd2f41c8 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.html @@ -0,0 +1,248 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler

+from contextlib import ExitStack
+from threading import RLock
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions import (
+    KiwoomOpenApiPlusEventHandlerFunctions,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import (
+    QueueBasedIterableObserver,
+)
+from koapy.utils.notimplemented import isimplemented
+
+
+
[docs]class KiwoomOpenApiPlusEventHandler(KiwoomOpenApiPlusEventHandlerFunctions): + # pylint: disable=abstract-method + + def __init__(self, control): + self._control = control + self._observer = QueueBasedIterableObserver() + self._enter_count = 0 + self._should_exit = False + self._stack = ExitStack() + self._lock = RLock() + + @property +
[docs] def control(self): + return self._control
+ + @property +
[docs] def observer(self): + return self._observer
+ + @classmethod +
[docs] def names(cls): + names = [ + name + for name in dir(KiwoomOpenApiPlusEventHandlerFunctions) + if name.startswith("On") + ] + return names
+ +
[docs] def slots(self): + names = self.names() + slots = [getattr(self, name) for name in names] + names_and_slots_implemented = [ + (name, slot) for name, slot in zip(names, slots) if isimplemented(slot) + ] + return names_and_slots_implemented
+ +
[docs] def connect(self): + for name, slot in self.slots(): + getattr(self.control, name).connect(slot)
+ +
[docs] def disconnect(self): + for name, slot in self.slots(): + getattr(self.control, name).disconnect(slot)
+ +
[docs] def on_enter(self): + pass
+ +
[docs] def on_exit(self, exc_type=None, exc_value=None, traceback=None): + pass
+ +
[docs] def add_callback(self, callback, *args, **kwargs): + self._stack.callback(callback, *args, **kwargs)
+ +
[docs] def enter(self): + with self._lock: + self.connect() + self.on_enter() + self._should_exit = True
+ +
[docs] def exit(self, exc_type=None, exc_value=None, traceback=None): + with self._lock: + if self._should_exit: + self.disconnect() + self.on_exit(exc_type, exc_value, traceback) + self._stack.__exit__(exc_type, exc_value, traceback) + self._should_exit = False
+ +
[docs] def stop(self): + return self.observer.stop()
+ +
[docs] def close(self): + self.exit() + self.stop()
+ + def __enter__(self): + with self._lock: + if self._enter_count == 0: + self.enter() + self._enter_count += 1 + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is not None: + return self.exit(exc_type, exc_value, traceback) + with self._lock: + if self._enter_count > 0: + self._enter_count -= 1 + if self._enter_count == 0: + return self.exit(exc_type, exc_value, traceback) + return + + def __iter__(self): + with self: + return iter(self.observer)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.html new file mode 100644 index 00000000..fa18f28c --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.html @@ -0,0 +1,192 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions

+from koapy.utils.notimplemented import notimplemented
+
+
+
[docs]class KiwoomOpenApiPlusEventHandlerFunctions: + @notimplemented +
[docs] def OnEventConnect(self, errcode): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveConditionVer(self, ret, msg): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + raise NotImplementedError
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.html new file mode 100644 index 00000000..420794ff --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.html @@ -0,0 +1,202 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature

+from __future__ import annotations
+
+from typing import Dict, List
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions import (
+    KiwoomOpenApiPlusEventFunctions,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature import (
+    KiwoomOpenApiPlusSignature,
+)
+from koapy.utils.builtin import dir_public
+
+
+
[docs]class KiwoomOpenApiPlusEventHandlerSignature(KiwoomOpenApiPlusSignature): + +
[docs] EVENT_HANDLER_SIGNATURES_BY_NAME: Dict[ + str, KiwoomOpenApiPlusEventHandlerSignature + ] = {}
+ + @classmethod +
[docs] def from_name(cls, name: str) -> KiwoomOpenApiPlusEventHandlerSignature: + signature = cls.EVENT_HANDLER_SIGNATURES_BY_NAME[name] + return signature
+ + @classmethod +
[docs] def names(cls) -> List[str]: + names = cls.EVENT_HANDLER_SIGNATURES_BY_NAME.keys() + names = list(names) + if not names: + _names = dir_public(KiwoomOpenApiPlusEventFunctions) + return names
+ + @classmethod + def _make_event_handler_signatures_by_name( + cls, + ) -> Dict[str, KiwoomOpenApiPlusEventHandlerSignature]: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( + EVENT_OLE_ITEM, + ) + + event = EVENT_OLE_ITEM + event_handler_signatures_by_name: Dict[ + str, KiwoomOpenApiPlusEventHandlerSignature + ] = {} + if event: + event_funcs = event.mapFuncs.items() + event_handler_signatures_by_name = {} + for func_name, entry in event_funcs: + signature = cls._from_entry(func_name, entry) + event_handler_signatures_by_name[func_name] = signature + return event_handler_signatures_by_name + + @classmethod + def _initialize(cls): + cls.EVENT_HANDLER_SIGNATURES_BY_NAME = ( + cls._make_event_handler_signatures_by_name() + )
+ + +KiwoomOpenApiPlusEventHandlerSignature._initialize() # pylint: disable=protected-access +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.html new file mode 100644 index 00000000..7ebc0f13 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.html @@ -0,0 +1,257 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler

+import datetime
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import (
+    KiwoomOpenApiPlusEventHandler,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusLoggingEventHandler(KiwoomOpenApiPlusEventHandler, Logging): +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + self.logger.debug( + "OnReceiveTrData(%r, %r, %r, %r, %r)", + scrnno, + rqname, + trcode, + recordname, + prevnext, + )
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata) + if code == "09" and realtype == "장시작시간": + signal_type = self.control.GetCommRealData(code, 215) + current_time = self.control.GetCommRealData(code, 20) + estimated_remaining_time = self.control.GetCommRealData(code, 214) + signal_type_msg = { + # 아래는 문서에서 확인 가능 + "0": "장시작전(동시호가시작,이후1분단위)", + "2": "장종료전(동시호가시작,이후1분단위)", + "3": "장시작(동시호가종료)", + "4": "장종료(동시호가종료)", + "8": "장종료(시간내용없음)", + "9": "장마감(시간내용없음)", + # 이후는 추정 + "s": "선물옵션장종료전(동시호가시작)", # 17번반복 + "a": "장후시간외종가시작", + "e": "선물옵션장종료(동시호가종료)", # 17번반복 + "b": "장후시간외종가종료", + "c": "시간외단일가시작", + "d": "시간외단일가종료", + }.get(signal_type, "알수없음") + if signal_type not in ["8", "9"]: + current_time = datetime.datetime.strptime(current_time, "%H%M%S") + else: + current_time = datetime.datetime.now() + ert = datetime.datetime.strptime(estimated_remaining_time, "%H%M%S") + estimated_remaining_time = datetime.timedelta( + hours=ert.hour, minutes=ert.minute, seconds=ert.second + ) + self.logger.debug( + "%s, %s remaining", signal_type_msg, estimated_remaining_time + )
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + """ + [OnReceiveMsg()이벤트] + + OnReceiveMsg( + BSTR sScrNo, // 화면번호 + BSTR sRQName, // 사용자 구분명 + BSTR sTrCode, // TR이름 + BSTR sMsg // 서버에서 전달하는 메시지 + ) + + 서버통신 후 수신한 메시지를 알려줍니다. + 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 + 이 코드번호로 분류하시면 안됩니다. + """ + self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg) + + if msg == "전문 처리 실패(-22)": + self.logger.warning("Server might have ended connection abruptly")
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist)
+ +
[docs] def OnEventConnect(self, errcode): + self.logger.debug("OnEventConnect(%r)", errcode)
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + self.logger.debug( + "OnReceiveRealCondition(%r, %r, %r, %r)", + code, + condition_type, + condition_name, + condition_index, + )
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + self.logger.debug( + "OnReceiveTrCondition(%r, %r, %r, %r, %r)", + scrnno, + codelist, + condition_name, + condition_index, + prevnext, + )
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + self.logger.debug("OnReceiveConditionVer(%r, %r)", ret, msg)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.html new file mode 100644 index 00000000..d0ff1336 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.html @@ -0,0 +1,301 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget

+from typing import Optional, overload
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import (
+    KiwoomOpenApiPlusDispatchSignature,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable import (
+    KiwoomOpenApiPlusDynamicCallable,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import (
+    KiwoomOpenApiPlusEventHandlerSignature,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler import (
+    KiwoomOpenApiPlusLoggingEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import (
+    KiwoomOpenApiPlusQAxWidgetMixin,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector import (
+    KiwoomOpenApiPlusSignalConnector,
+)
+from koapy.compat.pyside2.QtAxContainer import QAxWidget
+from koapy.compat.pyside2.QtCore import QEvent, Qt
+from koapy.compat.pyside2.QtWidgets import QWidget
+from koapy.utils.logging.pyside2.QWidgetLogging import QWidgetLogging
+from koapy.utils.platform import is_32bit
+
+
+
[docs]class KiwoomOpenApiPlusQAxWidget( + QWidgetLogging, + KiwoomOpenApiPlusQAxWidgetMixin, +): + +
[docs] CLSID = "{A1574A0D-6BFA-4BD7-9020-DED88711818D}"
+
[docs] PROGID = "KHOPENAPI.KHOpenApiCtrl.1"
+ +
[docs] METHOD_NAMES = KiwoomOpenApiPlusDispatchSignature.names()
+
[docs] EVENT_NAMES = KiwoomOpenApiPlusEventHandlerSignature.names()
+ + @overload + def __init__( + self, + c: Optional[str] = None, + parent: Optional[QWidget] = None, + f: Qt.WindowFlags = Qt.WindowFlags(), + ): + ... + + @overload + def __init__( + self, + parent: Optional[QWidget] = None, + f: Qt.WindowFlags = Qt.WindowFlags(), + ): + ... + + def __init__(self, *args, **kwargs): + # Check 32bit requirement + assert is_32bit(), "Control object should be created in 32bit environment" + + # Process arguments + control: Optional[str] = None + parent: Optional[QWidget] = None # pylint: disable=unused-variable + window_flags: Optional[Qt.WindowFlags] = None # pylint: disable=unused-variable + + # Copy args before modification + args = list(args) + kwargs = dict(kwargs) + + # Pop control argument for QWidget init + if len(args) > 0 and isinstance(args[0], str): + control = args.pop(0) + elif "c" in kwargs: + control = kwargs.pop("c") + + # Preserve others + if len(args) > 0 and (args[0] is None or isinstance(args[0], QWidget)): + parent = args[0] + elif "parent" in kwargs: + parent = kwargs["parent"] + + if len(args) > 1: + window_flags = args[1] + elif "f" in kwargs: + window_flags = kwargs["f"] + + # Use default control if not set + if control is None: + control = self.CLSID + + # Call super init + QWidgetLogging.__init__(self, *args, **kwargs) + + # Create QAxWidget + self._control = control + self._ax = QAxWidget(self._control, self) + + # Check if instantiation of the QAxWidget was successful + successful = not self._ax.isNull() + if not successful: + raise RuntimeError( + "Requested control {} could not be instantiated".format(self._control) + ) + + # Set methods as attributes + for method_name in self.METHOD_NAMES: + dynamic_callable = KiwoomOpenApiPlusDynamicCallable( + self._ax, method_name, parent=self + ) + setattr(self, method_name, dynamic_callable) + + # Set signals as attributes + for event_name in self.EVENT_NAMES: + signal_connector = KiwoomOpenApiPlusSignalConnector(event_name) + signal_connector.connect_to(self._ax) + setattr(self, event_name, signal_connector) + + # Call mixin init here, after method attributes are set + KiwoomOpenApiPlusQAxWidgetMixin.__init__(self) + + # Enable logging for QAxWidget exceptions + self._ax.exception.connect(self._onException) # pylint: disable=no-member + + # Enable logging for OpenAPI events + self._event_logger = KiwoomOpenApiPlusLoggingEventHandler(self) + self._event_logger.connect() + + # Other misc flags + self.hideOnMinimize = True + self.hideOnClose = True + + def _onException( + self, code, source, desc, help + ): # pylint: disable=redefined-builtin + self.logger.error("QAxBaseException(%r, %r, %r, %r)", code, source, desc, help) + + def __getattr__(self, name): + try: + # Fallback to AxObject for attrs such as 'self.dynamicCall(...)' + return getattr(self._ax, name) + except AttributeError as e: + raise AttributeError( + "'{}' object has no attribute '{}'".format( + self.__class__.__name__, name + ) + ) from e + +
[docs] def changeEvent(self, event): + if event.type() == QEvent.WindowStateChange: + if self.windowState() & Qt.WindowMinimized: + if self.hideOnMinimize: + self.hide() + return event.ignore() + return event.accept()
+ +
[docs] def closeEvent(self, event): + if self.hideOnClose: + self.hide() + return event.ignore() + return event.accept()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.html new file mode 100644 index 00000000..3bec6316 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.html @@ -0,0 +1,1419 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin

+import json
+import os
+import queue
+import subprocess
+
+from concurrent.futures import ThreadPoolExecutor
+from pathlib import Path
+from typing import Any, Callable, Dict, Mapping, Optional, Union, overload
+
+from wrapt import synchronized
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import (
+    KiwoomOpenApiPlusDispatchFunctions,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter import (
+    KiwoomOpenApiPlusCommRqDataRateLimiter,
+    KiwoomOpenApiPlusSendConditionRateLimiter,
+    KiwoomOpenApiPlusSendOrderRateLimiter,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.list_conversion import string_to_list
+from koapy.config import config
+from koapy.utils.ctypes import is_admin
+from koapy.utils.logging import get_verbosity
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor import QRateLimitedExecutor
+from koapy.utils.subprocess import Popen, function_to_subprocess_args
+
+
+
[docs]class KiwoomOpenApiPlusQAxWidgetUniversalMixin(KiwoomOpenApiPlusDispatchFunctions): + """ + 일차적으로 KiwoomOpenApiPlusQAxWidget 객체에 대해 사용될 수 있는 Mixin 이지만, + 넓게는 다른 KiwoomOpenApiPlusDispatchFunctions 인터페이스를 지원하는 모든 객체에서 사용될 수 있는, + 단순하면서도 유니버셜한 메소드들이 구현되어 있는 Mixin 입니다. + """ + +
[docs] def IsConnected(self): + """ + 키움증권 서버에 접속되었는지 여부를 반환합니다. + """ + return self.GetConnectState() == 1
+ +
[docs] def ShowAccountWindow(self): + """ + 계좌 비밀번호 및 자동 로그인 처리 관련 설정창을 표시합니다. + """ + return self.KOA_Functions("ShowAccountWindow", "")
+ +
[docs] def GetServerGubun(self): + """ + 접속된 서버의 종류를 확인해 구분값을 반환합니다. + """ + gubun = self.KOA_Functions("GetServerGubun", "") + if not gubun: + gubun = self.GetLoginInfo("GetServerGubun") + return gubun
+ +
[docs] def IsSimulationServer(self): + """ + 모의투자 서버 접속 여부를 확인해 반환합니다. + """ + gubun = self.GetServerGubun() + return gubun == "1"
+ +
[docs] def IsRealServer(self): + """ + 실 서버 접속 여부를 확인해 반환합니다. + """ + return not self.IsSimulationServer()
+ +
[docs] def GetMasterStockInfo(self, code): + """ + 주식의 종목분류, 시장구분등의 정보를 제공합니다. + """ + return self.KOA_Functions("GetMasterStockInfo", code)
+ +
[docs] def GetMasterStockInfoAsDict(self, code): + """ + 주식의 종목분류, 시장구분등의 정보를 딕셔너리 형태로 가공하여 제공합니다. + """ + result = self.GetMasterStockInfo(code) + items = string_to_list(result, sep=";") + items = [string_to_list(item, sep="|") for item in items] + info = dict(items) + return info
+ +
[docs] def SetConditionSearchFlag(self, flag): + """ + 조건 검색시 동작과 관련된 플래그를 설정합니다. + """ + return self.KOA_Functions("SetConditionSearchFlag", flag)
+ +
[docs] def AddPriceToConditionSearchResult(self): + """ + 조건 검색시 현재가를 함께 수신하도록 설정합니다. + """ + return self.SetConditionSearchFlag("AddPrice")
+ +
[docs] def DelPriceFromConditionSearchResult(self): + """ + 조건 검색시 현재가를 함께 수신하지 않도록 설정합니다. + """ + return self.SetConditionSearchFlag("DelPrice")
+ +
[docs] def GetUpjongCode(self, code): + """ + 업종코드 목록을 반환합니다. + + 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + """ + code = str(code) + return self.KOA_Functions("GetUpjongCode", code)
+ +
[docs] def GetUpjongCodeAsList(self, code): + """ + 업종코드 목록을 리스트 형태로 가공하여 반환합니다. + + 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + """ + result = self.GetUpjongCode(code) + items = string_to_list(result, sep="|") + items = [string_to_list(item, sep=",") for item in items] + items = [tuple(item) for item in items] + return items
+ +
[docs] def GetUpjongNameByCode(self, code): + """ + 주어진 업종코드의 이름을 반환합니다. + """ + return self.KOA_Functions("GetUpjongNameByCode", code)
+ +
[docs] def IsOrderWarningETF(self, code): + """ + ETF 의 투자유의 종목 여부를 반환합니다. + + 투자유의 종목인 경우 "1" 값이 리턴, + 그렇지 않은 경우 "0" 값 리턴. + ETF가 아닌 종목을 입력시 "0" 값 리턴. + """ + return self.KOA_Functions("IsOrderWarningETF", code)
+ +
[docs] def IsOrderWarningETFAsBoolean(self, code): + """ + ETF 의 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. + """ + return_code = self.IsOrderWarningETF(code) + return_code = int(return_code) + return_code = bool(return_code) + return return_code
+ +
[docs] def IsOrderWarningStock(self, code): + """ + 주식 전종목 대상 투자유의 종목 여부를 반환합니다. + + 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 + """ + return self.KOA_Functions("IsOrderWarningStock", code)
+ +
[docs] def IsOrderWarningStockAsBoolean(self, code): + """ + 주식 전종목 대상 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. + """ + return_code = self.IsOrderWarningStock(code) + return_code = int(return_code) + return_code = bool(return_code) + return return_code
+ +
[docs] def GetMasterListedStockCntEx(self, code): + """ + 종목의 상장 주식수를 반환합니다. + + 기존의 GetMasterListedStockCnt() 함수 사용시 발생할 수 있는 오버플로우 문제를 해결합니다. + """ + return self.KOA_Functions("GetMasterListedStockCntEx", code)
+ +
[docs] def GetMasterListedStockCntExAsInt(self, code): + """ + 종목의 상장 주식수를 정수 형태로 변환하여 반환합니다. + """ + count = self.GetMasterListedStockCntEx(code) + count = int(count) + return count
+ +
[docs] def GetCodeListByMarketAsList(self, market: Optional[Union[str, int]] = None): + """ + 시장의 종목 코드 목록를 리스트 형태로 가공하여 반환합니다. + """ + if market is None: + market = "" + market = str(market) + result = self.GetCodeListByMarket(market) + result = string_to_list(result) + return result
+ +
[docs] def GetNameListByMarketAsList(self, market: Optional[Union[str, int]] = None): + """ + 시장의 종목 이름 목록를 리스트 형태로 가공하여 반환합니다. + """ + codes = self.GetCodeListByMarketAsList(market) + names = [self.GetMasterCodeName(code) for code in codes] + return names
+ +
[docs] def GetUserId(self): + """ + 사용자 ID 를 반환합니다. + """ + userid = self.GetLoginInfo("USER_ID") + return userid
+ +
[docs] def GetUserName(self): + """ + 사용자 이름을 반환합니다. + """ + username = self.GetLoginInfo("USER_NAME") + return username
+ +
[docs] def GetAccountCount(self): + """ + 계좌 개수를 반환합니다. + """ + account_count = self.GetLoginInfo("ACCOUNT_CNT") + account_count = int(account_count) + return account_count
+ +
[docs] def GetAccountList(self): + """ + 계좌 목록을 리스트 형태로 가공하여 반환합니다. + """ + accounts = self.GetLoginInfo("ACCLIST") + accounts = string_to_list(accounts) + return accounts
+ +
[docs] def GetKeyboardSecurityStatus(self): + """ + 키보드 보안 설정 상태를 반환합니다. + """ + return self.GetLoginInfo("KEY_BSECGB")
+ +
[docs] def IsKeyboardSecurityEnabled(self): + """ + 키보드 보안 설정 상태를 불리언 형태로 변환하여 반환합니다. + """ + gubun = self.GetKeyboardSecurityStatus() + return gubun == "0"
+ +
[docs] def GetFirewallStatus(self): + """ + 방화벽 설정 상태를 반환합니다. + """ + return self.GetLoginInfo("FIREW_SECGB")
+ +
[docs] def IsFirewallEnabled(self): + """ + 방화벽 설정 상태를 불리언 형태로 변환하여 반환합니다. + """ + gubun = self.GetFirewallStatus() + return gubun == "1"
+ +
[docs] def GetFirstAvailableAccount(self): + """ + 확인 가능한 첫번째 계좌번호를 반환합니다. + """ + account = None + accounts = self.GetAccountList() + if len(accounts) > 0: + account = accounts[0] + return account
+ +
[docs] def GetMasterStockStateAsList(self, code: str): + """ + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 + 리스트 형태로 가공하여 전달합니다. + """ + states = self.GetMasterStockState(code).strip() + states = string_to_list(states, sep="|") + return states
+ +
[docs] def GetKospiCodeList(self): + """ + 장내 종목 코드 목록을 반환합니다. + """ + codes = self.GetCodeListByMarketAsList("0") + codes = sorted(codes) + return codes
+ +
[docs] def GetKosdaqCodeList(self): + """ + 코스닥 시장내 종목 코드 목록을 반환합니다. + """ + codes = self.GetCodeListByMarketAsList("10") + codes = sorted(codes) + return codes
+ +
[docs] def GetGeneralCodeList( + self, + include_preferred_stock: bool = False, + include_etn: bool = False, + include_etf: bool = False, + include_mutual_fund: bool = False, + include_reits: bool = False, + include_kosdaq: bool = False, + ): + """ + 장내 종목 코드 목록중 특정 그룹을 포함시키고 혹은 제거하고 반환합니다. + """ + + """ + [시장구분값] + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + """ + + codes = self.GetKospiCodeList() + + # 코드 마지막 자리가 0 이 아니면 우선주일 가능성이 있다고 보고 제외 + if not include_preferred_stock: + codes = [code for code in codes if code.endswith("0")] + + # 장내 시장에서 ETN 이 섞여 있는데 시장구분값으로 뺄 수가 없어서 이름을 보고 대충 제외 + if not include_etn: + names = [self.GetMasterCodeName(code) for code in codes] + etn_suffixes = ["ETN", "ETN(H)", "ETN B", "ETN(H) B"] + is_not_etn_name = [ + not any(name.endswith(suffix) for suffix in etn_suffixes) + for name in names + ] + codes = [code for code, cond in zip(codes, is_not_etn_name) if cond] + + # 코드값 기준 제외 준비 + codes = set(codes) + + # 나머지는 혹시나 겹치는 애들이 나올 수 있는 시장에서 코드기준 제외 + if not include_kosdaq: + codes = codes - set(self.GetCodeListByMarketAsList("10")) # 코스닥 + if not include_etf: + codes = codes - set(self.GetCodeListByMarketAsList("8")) # ETF + if not include_mutual_fund: + codes = codes - set(self.GetCodeListByMarketAsList("4")) # 뮤추얼펀드 + if not include_reits: + codes = codes - set(self.GetCodeListByMarketAsList("6")) # 리츠 + + # 정렬된 리스트 형태로 제공 + codes = sorted(list(codes)) + + return codes
+ +
[docs] def GetStockStates(self, code: str): + """ + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. + """ + return self.GetMasterStockStateAsList(code)
+ +
[docs] def GetSurveillanceFlag(self, code: str): + """ + 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + """ + return self.GetMasterConstruction(code)
+ +
[docs] def IsSuspended(self, code: str): + """ + 거래정지 여부를 반환합니다. + """ + return "거래정지" in self.GetMasterStockStateAsList(code)
+ +
[docs] def IsUnderSurveillance(self, code: str): + """ + 감리종목 여부를 반환합니다. + """ + return "감리종목" in self.GetMasterStockStateAsList(code)
+ +
[docs] def IsUnderAdministration(self, code: str): + """ + 관리종목 여부를 반환합니다. + """ + return "관리종목" in self.GetMasterStockStateAsList(code)
+ +
[docs] def IsFlaggedForCaution(self, code: str): + """ + 감리구분이 정상이 아니거나 상태값중 투자유의종목으로 지정된 경우 참을 반환합니다. + """ + flag = self.GetSurveillanceFlag(code) + states = self.GetMasterStockStateAsList(code) + flag_is_not_normal = flag != "정상" + has_caution_state = "투자유의종목" in states + return flag_is_not_normal or has_caution_state
+ +
[docs] def IsNotNormal(self, code: str): + """ + 감리구분이 정상이 아니거나 상태값중 거래정지, 감리종목, 관리종목, 투자유의종목 등으로 지정된 경우 참을 반환합니다. + """ + flag = self.GetSurveillanceFlag(code) + states = self.GetMasterStockStateAsList(code) + flag_is_not_normal = flag != "정상" + bad_states = ["거래정지", "감리종목", "관리종목", "투자유의종목"] + has_any_bad_state = any(state in states for state in bad_states) + return flag_is_not_normal or has_any_bad_state
+ +
[docs] def IsNormal(self, code: str): + """ + 감리구분이 정상이고 별다른 이상 상태값이 없는 경우 참을 반환합니다. + """ + return not self.IsNotNormal(code)
+ +
[docs] def GetConditionFilePath(self): + """ + 조건식 데이터를 로드한 후 생성되는 조건검색 관련 데이터 파일의 경로를 반환합니다. + """ + module_path = self.GetAPIModulePath() + module_path = Path(module_path) + userid = self.GetUserId() + condition_filepath = module_path / "system" / f"{userid}_NewSaveIndex.dat" + condition_filepath = str(condition_filepath) + return condition_filepath
+ +
[docs] def GetConditionNameListAsList(self): + """ + 조건식 데이터를 로드한 후 확인 가능한 조건식 목록을 리스트 형태로 가공하여 반환합니다. + """ + self.EnsureConditionLoaded() + conditions = self.GetConditionNameList() + conditions = string_to_list(conditions) + conditions = [string_to_list(cond, sep="^") for cond in conditions] + conditions = [(int(cond[0]), cond[1]) for cond in conditions] + return conditions
+ +
[docs] def GetAutoLoginDatPath(self): + """ + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일의 경로를 반환합니다. + """ + module_path = self.GetAPIModulePath() + module_path = Path(module_path) + autologin_dat = module_path / "system" / "Autologin.dat" + autologin_dat = str(autologin_dat) + return autologin_dat
+ +
[docs] def IsAutoLoginEnabled(self): + """ + 자동 로그인 설정 여부를 반환합니다. + + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는지의 여부를 확인합니다. + """ + autologin_dat = self.GetAutoLoginDatPath() + return os.path.exists(autologin_dat)
+ +
[docs] def DisableAutoLogin(self): + """ + 자동 로그인 설정을 해제합니다. + + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는 경우 해당 파일을 삭제합니다. + """ + autologin_dat = self.GetAutoLoginDatPath() + if os.path.exists(autologin_dat): + os.remove(autologin_dat)
+ + # ====================================================================== + + @classmethod +
[docs] def RunScriptInSubprocess_WithData( + cls, + main: Callable[..., Any], + data: Optional[Mapping[str, Any]] = None, + wait: bool = False, + timeout: bool = None, + check: bool = False, + stdin: Optional[int] = subprocess.PIPE, + stdout: Optional[int] = None, + ): + args = function_to_subprocess_args(main) + process = Popen(args, stdin=stdin, stdout=stdout, text=True) + json.dump(data, process.stdin) + + if wait: + try: + stdout, stderr = process.communicate(timeout=timeout) + except subprocess.TimeoutExpired as exc: + process.kill() + exc.stdout, exc.stderr = process.communicate() + raise exc + except: + process.kill() + raise + retcode = process.poll() + completed = subprocess.CompletedProcess( + process.args, retcode, stdout, stderr + ) + if check: + completed.check_returncode() + return completed + + return process
+ + @classmethod +
[docs] def LoginUsingPywinauto_Impl(cls, credentials: Optional[Mapping[str, Any]] = None): + import pywinauto + + if credentials is None: + credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") + + is_in_development = False + use_set_text = False + + userid = credentials.get("user_id") + password = credentials.get("user_password") + cert = credentials.get("cert_password") + + is_save_userid = True + is_simulation = credentials.get("is_simulation") + + desktop = pywinauto.Desktop(allow_magic_lookup=False) + login_window = desktop.window(title="Open API Login") + + try: + cls.logger.info("Waiting for login screen") + timeout_login_screen_ready = 30 + login_window.wait("ready", timeout_login_screen_ready) + except pywinauto.timings.TimeoutError: + cls.logger.info("Cannot find login screen") + raise + else: + cls.logger.info("Login screen found") + if is_in_development: + login_window.print_control_identifiers() + + if userid: + cls.logger.info("Putting userid") + if use_set_text: + login_window["Edit1"].set_text(userid) + else: + login_window["Edit1"].set_focus() + pywinauto.keyboard.send_keys(userid) + pywinauto.keyboard.send_keys("{TAB}") + if password: + cls.logger.info("Putting password") + if use_set_text: + login_window["Edit2"].set_text(password) + else: + login_window["Edit2"].set_focus() + pywinauto.keyboard.send_keys(password) + pywinauto.keyboard.send_keys("{TAB}") + else: + raise RuntimeError("'user_password' not set, please check credentials") + + if is_save_userid: + cls.logger.info("Checking to save userid") + login_window["Button6"].check() # check doesn't work + else: + cls.logger.info("Unchecking to save userid") + login_window["Button6"].uncheck() # uncheck doesn't work + + if not is_simulation: + if not login_window["Edit3"].is_enabled(): + cls.logger.info("Unchecking to use simulation server") + login_window["Button5"].uncheck_by_click() + if cert: + cls.logger.info("Putting cert password") + if use_set_text: + login_window["Edit3"].set_text(cert) + else: + login_window["Edit3"].set_focus() + pywinauto.keyboard.send_keys(cert) + pywinauto.keyboard.send_keys("{TAB}") + else: + raise RuntimeError( + "'cert_password' not set, please check credentials" + ) + else: + if login_window["Edit3"].is_enabled(): + cls.logger.info("Checking to use simulation server") + login_window["Button5"].check_by_click() + + cls.logger.info("Logging in") + login_window["Button1"].click()
+ + @classmethod +
[docs] def LoginUsingPywinauto_RunScriptInSubprocess( + cls, + credentials: Optional[Mapping[str, Any]] = None, + wait: bool = False, + timeout: bool = None, + check: bool = False, + ): + def main(): + # pylint: disable=redefined-outer-name,reimported,import-self + import json + import sys + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( + KiwoomOpenApiPlusQAxWidgetMixin, + ) + from koapy.utils.logging import set_verbosity + + data = json.load(sys.stdin) + credentials = data["credentials"] + verbosity = data["verbosity"] + set_verbosity(verbosity) + KiwoomOpenApiPlusQAxWidgetMixin.LoginUsingPywinauto_Impl(credentials) + + verbosity = get_verbosity() + data = { + "credentials": credentials, + "verbosity": verbosity, + } + + return cls.RunScriptInSubprocess_WithData( + main, + data, + wait=wait, + timeout=timeout, + check=check, + )
+ +
[docs] def LoginUsingPywinauto( + self, + credentials: Optional[Mapping[str, Any]] = None, + wait: bool = True, + timeout: bool = None, + check: bool = True, + ): + """ + 자식 프로세스 내에서 pywinauto 를 사용해 로그인 처리를 자동으로 진행합니다. + """ + assert is_admin(), "Using pywinauto requires administrator permission" + return self.LoginUsingPywinauto_RunScriptInSubprocess( + credentials, + wait=wait, + timeout=timeout, + check=check, + )
+ + @overload +
[docs] def CommConnectAndThen( + self, + credentials: Mapping[str, Any], + callback: Callable[[int], Any], + ) -> int: + ...
+ + @overload + def CommConnectAndThen(self, credentials: Mapping[str, Any]) -> int: + ... + + @overload + def CommConnectAndThen(self, callback: Callable[[int], Any]) -> int: + ... + + @overload + def CommConnectAndThen(self) -> int: + ... + + def CommConnectAndThen( + self, + credentials_or_callback=None, + callback_or_none=None, + ) -> int: + """ + 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 특정 콜백 함수를 실행합니다. + """ + credentials = credentials_or_callback + callback = callback_or_none + + if ( + callback is None + and credentials is not None + and not isinstance(credentials, dict) + and callable(credentials) + ): + callback = credentials + credentials = None + + can_use_pywinauto = is_admin() + should_use_pywinauto = credentials is not None + + if should_use_pywinauto: + assert ( + can_use_pywinauto + ), "CommConnectAndThen() method requires to be run as administrator if credentials argument was given explicitly" + + if should_use_pywinauto: + self.DisableAutoLogin() + + if credentials is None and not self.IsAutoLoginEnabled() and can_use_pywinauto: + credentials = config.get( + key="koapy.backend.kiwoom_open_api_plus.credentials", + default=None, + ) + should_use_pywinauto = credentials is not None + + def OnEventConnect(errcode): + self.OnEventConnect.disconnect(OnEventConnect) + if callable(callback): + callback(errcode) + + self.OnEventConnect.connect(OnEventConnect) + errcode = KiwoomOpenApiPlusError.try_or_raise(self.CommConnect()) + + if should_use_pywinauto and not self.IsAutoLoginEnabled(): + process = self.LoginUsingPywinauto(credentials, wait=False) + + return errcode + +
[docs] def Connect(self, credentials: Optional[Mapping[str, Any]] = None) -> int: + """ + 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 확인 가능한 에러코드 값을 반환합니다. + """ + q = queue.Queue() + + def OnEventConnect(errcode): + q.put(errcode) + + errcode = self.CommConnectAndThen(credentials, OnEventConnect) + errcode = KiwoomOpenApiPlusError.try_or_raise(q.get()) + + return errcode
+ + @overload +
[docs] def EnsureConnectedAndThen( + self, + credentials: Mapping[str, Any], + callback: Callable[[int], Any], + ) -> bool: + ...
+ + @overload + def EnsureConnectedAndThen(self, credentials: Mapping[str, Any]) -> bool: + ... + + @overload + def EnsureConnectedAndThen(self, callback: Callable[[int], Any]) -> bool: + ... + + @overload + def EnsureConnectedAndThen(self) -> bool: + ... + + def EnsureConnectedAndThen( + self, + credentials_or_callback=None, + callback_or_none=None, + ) -> bool: + """ + 로그인 여부를 확인하고 로그인 상태를 보장한 뒤에 주어진 콜백 함수를 실행합니다. + + 로그인 여부 확인시 로그인 되어있지 않다면 로그인을 진행한 뒤 주어진 콜백 함수를 실행합니다. + 이미 로그인이 되어있다면 즉시 주어진 콜백 함수를 실행합니다. + """ + credentials = credentials_or_callback + callback = callback_or_none + + if ( + callback is None + and credentials is not None + and not isinstance(credentials, dict) + and callable(credentials) + ): + callback = credentials + credentials = None + + is_connected = self.IsConnected() + + if not is_connected: + + def OnEventConnect(errcode): + if errcode == 0: + if callable(callback): + callback(errcode) + + errcode = self.CommConnectAndThen(credentials, OnEventConnect) + else: + if callable(callback): + errcode = 0 + callback(errcode) + + return is_connected + +
[docs] def EnsureConnected(self, credentials: Optional[Mapping[str, Any]] = None) -> bool: + """ + 로그인 상태를 보장하도록 합니다. + + 이미 로그인이 되어있는 경우 별다른 처리를 하지 않습니다. + 로그인이 되어있지 않다면 로그인을 수행합니다. + """ + is_connected = self.IsConnected() + if not is_connected: + self.Connect(credentials) + is_connected = self.IsConnected() + assert is_connected, "Could not ensure connected" + return is_connected
+ + @classmethod +
[docs] def EnableAutoLoginUsingPywinauto_Impl( + cls, account_passwords: Optional[Mapping[str, Any]] = None + ): + import pywinauto + + if account_passwords is None: + credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") + account_passwords = credentials.get("account_passwords") + + is_in_development = False + + desktop = pywinauto.Desktop(allow_magic_lookup=False) + account_window = desktop.window(title_re=r"계좌비밀번호 입력 \(버전: [0-9]+.+[0-9]+\)") + + try: + cls.logger.info("Waiting for account window to show up") + timeout_account_window_ready = 15 + account_window.wait("ready", timeout_account_window_ready) + except pywinauto.timings.TimeoutError: + cls.logger.info("Cannot find account window") + raise + else: + cls.logger.info("Account window found") + if is_in_development: + account_window.print_control_identifiers() + + cls.logger.info("Enabling auto login") + account_window["CheckBox"].check() + + account_combo = account_window["ComboBox"] + account_cnt = account_combo.item_count() + + cls.logger.info("Putting account passwords") + for i in range(account_cnt): + account_combo.select(i) + account_no = account_combo.selected_text().split()[0] + if account_no in account_passwords: + account_window["Edit"].set_text(account_passwords[account_no]) + elif "0000000000" in account_passwords: + account_window["Edit"].set_text(account_passwords["0000000000"]) + account_window["등록"].click() + + cls.logger.info("Closing account window") + account_window["닫기"].click() + + try: + cls.logger.info("Waiting account window to be closed") + timeout_account_window_done = 5 + account_window.wait_not("visible", timeout_account_window_done) + except pywinauto.timings.TimeoutError as e: + cls.logger.info("Cannot sure account window is closed") + raise RuntimeError("Cannot sure account window is closed") from e + else: + cls.logger.info("Account window closed")
+ + @classmethod +
[docs] def EnableAutoLoginUsingPywinauto_RunScriptInSubprocess( + cls, + account_passwords: Optional[Mapping[str, Any]] = None, + wait: bool = False, + timeout: bool = None, + check: bool = False, + ): + def main(): + # pylint: disable=redefined-outer-name,reimported,import-self + import json + import sys + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( + KiwoomOpenApiPlusQAxWidgetMixin, + ) + from koapy.utils.logging import set_verbosity + + data = json.load(sys.stdin) + account_passwords = data["account_passwords"] + verbosity = data["verbosity"] + set_verbosity(verbosity) + KiwoomOpenApiPlusQAxWidgetMixin.EnableAutoLoginUsingPywinauto_Impl( + account_passwords + ) + + verbosity = get_verbosity() + data = { + "account_passwords": account_passwords, + "verbosity": verbosity, + } + + return cls.RunScriptInSubprocess_WithData( + main, + data, + wait=wait, + timeout=timeout, + check=check, + )
+ +
[docs] def EnableAutoLoginUsingPywinauto( + self, + credentials: Optional[Mapping[str, Any]] = None, + wait: bool = True, + timeout: bool = None, + check: bool = True, + ): + """ + 자식 프로세스 내에서 pywinauto 를 사용해 자동 로그인 설정을 자동으로 진행합니다. + """ + assert is_admin(), "Using pywinauto requires administrator permission" + return self.EnableAutoLoginUsingPywinauto_RunScriptInSubprocess( + credentials, + wait=wait, + timeout=timeout, + check=check, + )
+ +
[docs] def EnableAutoLogin(self, credentials: Optional[Mapping[str, Any]] = None): + """ + 자동 로그인을 설정합니다. + """ + q = queue.Queue() + + def callback(errcode): + with ThreadPoolExecutor(1) as executor: + future = executor.submit(self.ShowAccountWindow) + self.EnableAutoLoginUsingPywinauto(credentials) + future.result() + q.put(errcode) + + self.EnsureConnectedAndThen(credentials, callback) + errcode = KiwoomOpenApiPlusError.try_or_raise(q.get()) + is_enabled = self.IsAutoLoginEnabled() + return is_enabled
+ +
[docs] def EnsureAutoLoginEnabled( + self, credentials: Optional[Mapping[str, Any]] = None + ) -> bool: + """ + 자동 로그인이 설정되어 있음을 보장하도록 합니다. + + 이미 자동 로그인이 설정 되어있는 경우 별다른 처리를 하지 않습니다. + 자동 로그인이 설정되어 있지 않다면 자동 로그인을 설정을 처리합니다. + """ + is_enabled = self.IsAutoLoginEnabled() + if not is_enabled: + self.EnableAutoLogin(credentials) + is_enabled = self.IsAutoLoginEnabled() + assert is_enabled, "Could not ensure auto login enabled" + return is_enabled
+ + @classmethod +
[docs] def HandleVersionUpgradeUsingPywinauto_Impl(cls, pid): + import psutil + import pywinauto + + desktop = pywinauto.Desktop(allow_magic_lookup=False) + login_window = desktop.window(title="Open API Login") + + timeout_login_successful = 4 + timeout_version_check = 1 + timeout_per_trial = timeout_login_successful + timeout_version_check + + trial_timeout = 180 + trial_count = trial_timeout / timeout_per_trial + + while trial_count > 0: + try: + cls.logger.info( + "Login in progress ... timeout after %d sec", + trial_count * timeout_per_trial, + ) + trial_count -= 1 + login_window.wait_not("exists", timeout_login_successful) + if login_window.exists(): + # make sure that login_window control does not exist. + continue + except pywinauto.timings.TimeoutError as e: + version_window = desktop.window(title="opstarter") + try: + version_window.wait("ready", timeout_version_check) + except pywinauto.timings.TimeoutError: + continue + else: + cls.logger.info("Version update required") + + cls.logger.info("Closing login app") + login_window_proc = psutil.Process(pid) + login_window_proc.kill() + login_window_proc.wait() + cls.logger.info("Killed login app process") + timeout_login_screen_closed = 30 + login_window.close(timeout_login_screen_closed) + try: + login_window.wait_not("visible", timeout_login_screen_closed) + except pywinauto.timings.TimeoutError as e: + cls.logger.warning("Cannot close login window") + raise RuntimeError("Cannot close login window") from e + else: + cls.logger.info("Closed login window") + + cls.logger.info("Starting to update version") + version_window["Button"].click() + + versionup_window = desktop.window(title="opversionup") + confirm_window = desktop.window(title="업그레이드 확인") + + try: + cls.logger.info("Waiting for possible failure") + timeout_confirm_update = 10 + versionup_window.wait("ready", timeout_confirm_update) + except pywinauto.timings.TimeoutError: + cls.logger.info("Cannot find failure confirmation popup") + else: + cls.logger.warning("Failed to update") + raise RuntimeError("Failed to update") from e + + try: + cls.logger.info( + "Waiting for confirmation popup after update" + ) + timeout_confirm_update = 10 + confirm_window.wait("ready", timeout_confirm_update) + except pywinauto.timings.TimeoutError as e: + cls.logger.warning("Cannot find confirmation popup") + raise RuntimeError("Cannot find confirmation popup") from e + else: + cls.logger.info("Confirming update") + confirm_window["Button"].click() + + cls.logger.info("Done update") + return True + else: + cls.logger.info("Login ended successfully") + cls.logger.info("No version update required") + return False + return False
+ + @classmethod +
[docs] def HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess( + cls, + pid: int, + wait: bool = False, + timeout: bool = None, + check: bool = False, + ): + def main(): + # pylint: disable=redefined-outer-name,reimported,import-self + import json + import sys + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( + KiwoomOpenApiPlusQAxWidgetMixin, + ) + from koapy.utils.logging import set_verbosity + + data = json.load(sys.stdin) + pid = data["pid"] + verbosity = data["verbosity"] + set_verbosity(verbosity) + is_updated = ( + KiwoomOpenApiPlusQAxWidgetMixin.HandleVersionUpgradeUsingPywinauto_Impl( + pid + ) + ) + result = {"is_updated": is_updated} + json.dump(result, sys.stdout) + + verbosity = get_verbosity() + data = { + "pid": pid, + "verbosity": verbosity, + } + + completed = cls.RunScriptInSubprocess_WithData( + main, + data, + wait=wait, + timeout=timeout, + check=check, + stdout=subprocess.PIPE, + ) + result = json.loads(completed.stdout) + is_updated = result["is_updated"] + return is_updated
+ +
[docs] def HandleVersionUpgradeUsingPywinauto( + self, + pid: int, + wait: bool = True, + timeout: bool = None, + check: bool = True, + ): + """ + 자식 프로세스 내에서 pywinauto 를 사용해 버전 업그레이드 처리를 자동으로 진행합니다. + """ + assert is_admin(), "Using pywinauto requires administrator permission" + return self.HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess( + pid, + wait=wait, + timeout=timeout, + check=check, + )
+ + +
[docs]class KiwoomOpenApiPlusQAxWidgetServerSideMixin( + KiwoomOpenApiPlusDispatchFunctions, Logging +): + """ + KiwoomOpenApiPlusQAxWidget 객체에 대해 Server-Side 에서만 사용되는 Mixin 입니다. + + 주로 서버 환경에서만 확인하거나 처리가 가능한 아래 기능들을 커버합니다: + + - 조건검색식 로드 + - 조회 횟수 제한 회피 기능 + """ + + def __init__(self): + """ + 조건검색식 로드 및 조회 횟수 제한 회피 기능 관련 초기화를 진행합니다. + """ + + """ + [OpenAPI 게시판] + https://bbn.kiwoom.com/bbn.openAPIQnaBbsList.do + + [조회횟수 제한 관련 가이드] + - 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기 + - 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기 + - 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기 + """ + + """ + [조회제한] + OpenAPI 조회는 1초당 5회로 제한되며 복수종목 조회와 조건검색 조회 횟수가 합산됩니다. + 가령 1초 동안 시세조회2회 관심종목 1회 조건검색 2회 순서로 조회를 했다면 모두 합쳐서 5회이므로 모두 조회성공하겠지만 + 조건검색을 3회 조회하면 맨 마지막 조건검색 조회는 실패하게 됩니다. + + [조건검색 제한] + 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다. + """ + + self._comm_rate_limiter = KiwoomOpenApiPlusCommRqDataRateLimiter() + self._cond_rate_limiter = KiwoomOpenApiPlusSendConditionRateLimiter( + self._comm_rate_limiter + ) + self._order_rate_limiter = KiwoomOpenApiPlusSendOrderRateLimiter() + + self._comm_rate_limited_executor = QRateLimitedExecutor( + self._comm_rate_limiter, self + ) + self._cond_rate_limited_executor = QRateLimitedExecutor( + self._cond_rate_limiter, self + ) + self._order_rate_limited_executor = QRateLimitedExecutor( + self._order_rate_limiter, self + ) + + self.RateLimitedCommRqData = self._comm_rate_limited_executor.wrap( + self.CommRqDataWithInputs + ) + self.RateLimitedCommKwRqData = self._comm_rate_limited_executor.wrap( + self.CommKwRqData + ) + self.RateLimitedSendCondition = self._cond_rate_limited_executor.wrap( + self.SendCondition + ) + self.RateLimitedSendOrder = self._order_rate_limited_executor.wrap( + self.SendOrder + ) + + self._is_condition_loaded = False + + self._comm_rate_limited_executor.start() + self._cond_rate_limited_executor.start() + self._order_rate_limited_executor.start() + + self.destroyed.connect(self._comm_rate_limited_executor.shutdown) + self.destroyed.connect(self._cond_rate_limited_executor.shutdown) + self.destroyed.connect(self._order_rate_limited_executor.shutdown) + +
[docs] def LoadCondition(self) -> int: + """ + 조건검색 관련 조건식을 불러옵니다. + """ + q = queue.Queue() + + def OnReceiveConditionVer(ret, msg): + if not ret: + q.put(KiwoomOpenApiPlusError(msg)) + else: + q.put((ret, msg)) + + self.OnReceiveConditionVer.connect(OnReceiveConditionVer) + try: + return_code = KiwoomOpenApiPlusError.try_or_raise_boolean( + self.GetConditionLoad(), "Failed to load condition" + ) + res = q.get() + if isinstance(res, KiwoomOpenApiPlusError): + raise res + except: # pylint: disable=try-except-raise + raise + else: + if return_code == 1: + self._is_condition_loaded = True + finally: + self.OnReceiveConditionVer.disconnect(OnReceiveConditionVer) + return return_code
+ +
[docs] def IsConditionLoaded(self) -> bool: + """ + 조건식이 로드 되었는지 여부를 반환합니다. + """ + # the original implementation of this function was like the following: + # condition_filepath = self.GetConditionFilePath() + # return os.path.exists(condition_filepath) + # this implementation was based on the description of `GetConditionLoad()` function in the official documentation + # which was like, "the temporary condition file would be deleted on after OCX program exits". + # but actually it turned out that existence of this file could not guarantee that the condition is actually loaded or not + # so here we are using entrypoint-wide member variable to remember once the condition is loaded + return self._is_condition_loaded
+ +
[docs] def EnsureConditionLoaded(self, force: bool = False) -> int: + """ + 조건식이 로드됨을 보장하도록 합니다. + + 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. + 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. + """ + return_code = 0 + is_condition_loaded = self.IsConditionLoaded() + if not is_condition_loaded or force: + return_code = self.LoadCondition() + else: + return_code = 1 + assert return_code == 1, "Could not ensure condition loaded" + return return_code
+ +
[docs] def CommRqDataWithInputs( + self, + rqname: str, + trcode: str, + prevnext: Union[str, int], + scrnno: str, + inputs: Optional[Dict[str, str]] = None, + ) -> int: + """ + CommRqData() 호출 이전에 주어진 입력값을로 SetInputValue() 호출을 통한 입력값 설정을 진행합니다. + 이후 CommRqData() 를 호출합니다. + """ + if inputs: + for k, v in inputs.items(): + self.SetInputValue(k, v) + prevnext = int(prevnext) # ensure prevnext is int + code = self.CommRqData(rqname, trcode, prevnext, scrnno) + return code
+ + @synchronized +
[docs] def AtomicCommRqData( + self, + rqname: str, + trcode: str, + prevnext: Union[str, int], + scrnno: str, + inputs: Optional[Dict[str, str]] = None, + ) -> int: + """ + SetInputValue() 호출을 통한 입력값 설정 및 CommRqData() 호출을 하나의 단위로 처리할 수 있도록 Lock 을 걸고 처리합니다. + """ + return self.CommRqDataWithInputs(rqname, trcode, prevnext, scrnno, inputs)
+ + +
[docs]class KiwoomOpenApiPlusQAxWidgetMixin( + KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin +): + """ + KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 + KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다. + """
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.html new file mode 100644 index 00000000..d714b65e --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.html @@ -0,0 +1,245 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter

+import threading
+import time
+
+from koapy.utils.rate_limiting.RateLimiter import (
+    CompositeTimeWindowRateLimiter,
+    RateLimiter,
+    TimeWindowRateLimiter,
+)
+
+
+
[docs]class KiwoomOpenApiPlusCommRqDataRateLimiter(CompositeTimeWindowRateLimiter): + + # [조회횟수 제한 관련] + # 단순하게 1초당 5회로 날리다보면 장기적으로 결국 막히기 때문에 기존에는 4초당 1회로 제한했었음 (3초당 1회부턴 제한걸림) + # 이후 1시간에 1000회로 제한한다는 추측이 있는데 일리 있어 보여서 도입 (http://blog.quantylab.com/htsapi.html) + # 1초당 1회로 계산했을때 1시간이면 3600 회, 주기를 1초씩 늘려보면 + # 2초당 1회 => 1800 > 1000, 3초당 1회 => 1200 > 1000, 4초당 1회 => 900 < 1000 + + """ + [조회횟수 제한 관련 가이드] + - 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기 + - 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기 + - 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기 + """ + + def __init__(self): + limiters = [ + TimeWindowRateLimiter(18, 5), + TimeWindowRateLimiter(90, 25), + TimeWindowRateLimiter(180, 50), + TimeWindowRateLimiter(3600, 1000), + ] + super().__init__(limiters)
+ + +
[docs]class KiwoomOpenApiPlusSendOrderRateLimiter(TimeWindowRateLimiter): + def __init__(self): + super().__init__(1, 5)
+ + +
[docs]class KiwoomOpenApiPlusSendConditionRateLimiter(RateLimiter): + # pylint: disable=arguments-differ + + """ + [조건검색 제한] + - 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다. + + [조건검색 제한] + 조건검색 요청은 1초당 5회 조회횟수 제한에 포함됩니다. + 동일 조건식에 대한 조건검색 요청은 1분에 1회로 제한됩니다. + 조건검색 결과가 100종목을 넘게 되면 해당조건은 실시간 조건검색 신호를 수신할 수 없습니다. + 실시간 조건검색은 최대 10개까지 사용 가능합니다. + """ + + def __init__(self, comm_rate_limiter): + self._lock = threading.RLock() + + self._comm_rate_limiter = comm_rate_limiter + self._limiters_per_condition = {} + +
[docs] def get_limiter_per_condition(self, condition_name, condition_index): + limiter_key = (condition_name, condition_index) + if limiter_key not in self._limiters_per_condition: + self._limiters_per_condition[limiter_key] = TimeWindowRateLimiter(60, 1) + limiter_per_condition = self._limiters_per_condition[limiter_key] + return limiter_per_condition
+ +
[docs] def check_sleep_seconds(self, fn, *args, **kwargs): + condition_name = None + condition_index = None + if fn.__name__ == "SendCondition": + condition_name = kwargs.get("condition_name", args[1]) + condition_index = kwargs.get("condition_index", args[2]) + with self._lock: + sleep_seconds = self._comm_rate_limiter.check_sleep_seconds() + if condition_name is not None and condition_index is not None: + limiter_per_condition = self.get_limiter_per_condition( + condition_name, condition_index + ) + sleep_seconds = max( + sleep_seconds, limiter_per_condition.check_sleep_seconds() + ) + return sleep_seconds
+ +
[docs] def add_call_history(self, fn, *args, **kwargs): + condition_name = None + condition_index = None + if fn.__name__ == "SendCondition": + condition_name = kwargs.get("condition_name", args[1]) + condition_index = kwargs.get("condition_index", args[2]) + with self._lock: + self._comm_rate_limiter.add_call_history() + if condition_name is not None and condition_index is not None: + limiter_per_condition = self.get_limiter_per_condition( + condition_name, condition_index + ) + limiter_per_condition.add_call_history()
+ +
[docs] def sleep_if_necessary(self, fn, *args, **kwargs): + with self._lock: + sleep_seconds = self.check_sleep_seconds(fn, *args, **kwargs) + if sleep_seconds > 0: + time.sleep(sleep_seconds)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.html new file mode 100644 index 00000000..8e1cfbd4 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.html @@ -0,0 +1,480 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType

+from __future__ import annotations
+
+import contextlib
+import json
+
+from os import PathLike
+from pathlib import Path
+from typing import BinaryIO, Dict, List, Optional, TextIO, Union
+
+import pandas as pd
+
+from koapy.config import debug, default_encoding
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.serialization import JsonSerializable
+
+
+
[docs]class KiwoomOpenApiPlusRealType(JsonSerializable, Logging): +
[docs] class Fid(JsonSerializable): + + __outer_class__ = None + +
[docs] FID_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata"
+
[docs] FID_DUMP_FILENAME = "fid.csv"
+
[docs] FID_DUMP_FILEPATH = FID_DUMP_FILEDIR / FID_DUMP_FILENAME
+
[docs] FID_DUMP_PROCESSOR = pd.read_csv
+ +
[docs] FID_BY_FID: Dict[int, KiwoomOpenApiPlusRealType.Fid] = {}
+
[docs] FID_BY_NAME: Dict[str, KiwoomOpenApiPlusRealType.Fid] = {}
+ + def __init__(self, fid: Optional[int] = None, name: Optional[str] = None): + if fid is not None and name is None: + name = self.get_name_by_fid(fid) + self.fid = fid + self.name = name + + def __repr__(self): + return "{}.{}({!r}, {!r})".format( + self.__outer_class__.__name__, + self.__class__.__name__, + self.fid, + self.name, + ) + + def __eq__(self, other): + if isinstance(other, type(self)): + return self.fid == other.fid and self.name == other.name + return False + + @classmethod +
[docs] def fids_from_dump_file( + cls, + dump_file: Optional[Union[str, PathLike]] = None, + encoding: Optional[str] = None, + ) -> Dict[int, str]: + if dump_file is None: + dump_file = cls.FID_DUMP_FILEPATH + if encoding is None: + encoding = "utf-8" + df = cls.FID_DUMP_PROCESSOR(dump_file, encoding=encoding) + fids = [cls(pair[0], pair[1]) for pair in zip(df["fid"], df["name"])] + return fids
+ + @classmethod +
[docs] def load_from_dump_file(cls, dump_file: Optional[Union[str, PathLike]] = None): + fids = cls.fids_from_dump_file(dump_file) + cls.FID_BY_FID = {fid.fid: fid for fid in fids} + cls.FID_BY_NAME = {fid.name: fid for fid in fids}
+ + @classmethod +
[docs] def from_fid( + cls, fid: Union[str, int] + ) -> Optional[KiwoomOpenApiPlusRealType.Fid]: + fid = int(fid) + fid = cls.FID_BY_FID.get(fid) + return fid
+ + @classmethod +
[docs] def from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType.Fid]: + fid = cls.FID_BY_NAME.get(name) + return fid
+ + @classmethod +
[docs] def get_name_by_fid( + cls, fid: Union[str, int], default: Optional[str] = None + ) -> Optional[str]: + fid = cls.from_fid(fid) + return fid.name if fid else default
+ +
[docs] REALTYPE_BY_DESC_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata"
+
[docs] REALTYPE_BY_DESC_DUMP_FILENAME = "realtype_by_desc.json"
+
[docs] REALTYPE_BY_DESC_DUMP_FILEPATH = ( + REALTYPE_BY_DESC_DUMP_FILEDIR / REALTYPE_BY_DESC_DUMP_FILENAME + )
+ +
[docs] REALTYPE_BY_DESC: Dict[str, KiwoomOpenApiPlusRealType] = {}
+ + def __init__( + self, + gidc: Optional[str] = None, + desc: Optional[str] = None, + nfid: Optional[int] = None, + fids: Optional[List[int]] = None, + ): + self.gidc = gidc + self.desc = desc + self.nfid = nfid + self.fids = fids + + def __repr__(self): + return "{}({!r}, {!r}, {!r}, {!r})".format( + self.__class__.__name__, + self.gidc, + self.desc, + self.nfid, + self.fids, + ) + + def __eq__(self, other): + if isinstance(other, type(self)): + return ( + self.gidc == other.gidc + and self.desc == other.desc + and self.nfid == other.nfid + and self.fids == other.fids + ) + return False + + @classmethod +
[docs] def get_realtype_name_list(cls): + return list(cls.REALTYPE_BY_DESC.keys())
+ + @classmethod +
[docs] def get_realtype_info_list(cls): + return list(cls.REALTYPE_BY_DESC.values())
+ + @classmethod +
[docs] def get_realtype_info_by_desc( + cls, desc: str + ) -> Optional[KiwoomOpenApiPlusRealType]: + return cls.REALTYPE_BY_DESC.get(desc)
+ + @classmethod +
[docs] def get_realtype_info_by_name( + cls, name: str + ) -> Optional[KiwoomOpenApiPlusRealType]: + return cls.get_realtype_info_by_desc(name)
+ + @classmethod +
[docs] def get_realtype_info_by_realtype_name( + cls, name: str + ) -> Optional[KiwoomOpenApiPlusRealType]: + return cls.get_realtype_info_by_name(name)
+ + @classmethod +
[docs] def from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType]: + return cls.get_realtype_info_by_name(name)
+ + @classmethod +
[docs] def get_fids_by_realtype_name(cls, name: str) -> Optional[List[int]]: + result = cls.get_realtype_info_by_realtype_name(name) + if result is not None: + return result.fids + return None
+ + @classmethod +
[docs] def get_fids_by_realtype_name_as_string(cls, name: str) -> Optional[str]: + fids = cls.get_fids_by_realtype_name(name) + if fids is not None: + fids = [str(fid) for fid in fids] + fids = ";".join(fids) + return fids
+ + @classmethod +
[docs] def get_field_names_by_realtype_name(cls, name: str) -> Optional[List[str]]: + fids = cls.get_fids_by_realtype_name(name) + names = None + if fids is not None: + names = [cls.Fid.get_name_by_fid(fid, str(fid)) for fid in fids] + return names
+ + @classmethod +
[docs] def realtypes_from_datfile( + cls, + dat_file: Optional[Union[str, PathLike, BinaryIO]] = None, + encoding: Optional[str] = None, + module_path: Optional[str] = None, + ) -> List[KiwoomOpenApiPlusRealType]: + if dat_file is None: + if module_path is None: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + module_path = API_MODULE_PATH + dat_file = module_path / "data" / "nkrealtime.dat" + + if isinstance(dat_file, str): + dat_file = Path(dat_file) + + if encoding is None: + encoding = "euc-kr" + + gidc_width = 2 + desc_width = 20 + nfid_width = 3 + fid_width = 5 + + with contextlib.ExitStack() as stack: + if isinstance(dat_file, Path): + if debug: + cls.logger.debug("Reading file %s", dat_file) + dat_file = open(dat_file, "rb") + dat_file = stack.enter_context(dat_file) + lines = iter(dat_file) + lines = map(lambda line: line.rstrip(b"\r\n"), lines) + lines = filter(lambda line: not line.startswith(b";"), lines) + realtypes = [] + for line in lines: + gidc = line[:gidc_width] + line = line[gidc_width:] + gidc = gidc.decode(encoding).strip() + desc = line[:desc_width] + line = line[desc_width:] + desc = desc.decode(encoding).strip() + nfid = line[:nfid_width] + nfid = nfid.strip() + line = line[nfid_width:] + if len(nfid) > 0: + nfid = int(nfid) + else: + nfid = 0 + fids = [] + for _ in range(nfid): + fid = line[:fid_width] + line = line[fid_width:] + fid = int(fid) + fids.append(fid) + assert len(line.rstrip(b"^M ")) == 0 + realtypes.append(cls(gidc, desc, nfid, fids)) + return realtypes
+ + @classmethod +
[docs] def realtype_by_desc_from_datfile( + cls, dat_file: Optional[Union[str, PathLike, BinaryIO]] = None + ) -> Dict[str, KiwoomOpenApiPlusRealType]: + realtypes = cls.realtypes_from_datfile(dat_file) + result = {realtype.desc: realtype for realtype in realtypes} + return result
+ + @classmethod +
[docs] def dump_realtype_by_desc( + cls, + dump_file: Optional[Union[str, PathLike, TextIO]] = None, + dat_file: Optional[Union[str, PathLike, BinaryIO]] = None, + encoding: Optional[str] = None, + ): + if dump_file is None: + dump_file = cls.REALTYPE_BY_DESC_DUMP_FILEPATH + if isinstance(dump_file, str): + dump_file = Path(dump_file) + with contextlib.ExitStack() as stack: + if isinstance(dump_file, PathLike): + dump_filename = dump_file + if encoding is None: + encoding = default_encoding + dump_file = open(dump_file, "w", encoding=encoding) + dump_file = stack.enter_context(dump_file) + else: + dump_filename = None + result = cls.realtype_by_desc_from_datfile(dat_file) + for tr_code in result: + result[tr_code] = result[tr_code].to_dict() + if dump_filename is not None: + cls.logger.debug("Saving realtype to %s", dump_filename) + return json.dump( + result, + dump_file, + indent=4, + sort_keys=True, + ensure_ascii=False, + )
+ + @classmethod +
[docs] def realtype_by_desc_from_dump_file( + cls, + dump_file: Optional[Union[str, PathLike, TextIO]] = None, + encoding: Optional[str] = None, + ) -> Dict[str, KiwoomOpenApiPlusRealType]: + if dump_file is None: + dump_file = cls.REALTYPE_BY_DESC_DUMP_FILEPATH + if isinstance(dump_file, str): + dump_file = Path(dump_file) + with contextlib.ExitStack() as stack: + if isinstance(dump_file, PathLike): + if dump_file.exists() and dump_file.stat().st_size > 0: + if encoding is None: + encoding = default_encoding + dump_file = open(dump_file, "r", encoding=encoding) + dump_file = stack.enter_context(dump_file) + else: + return {} + result = json.load(dump_file) + for desc in result: + result[desc] = cls.from_dict(result[desc]) + return result
+ + @classmethod +
[docs] def load_from_dump_file( + cls, dump_file: Optional[Union[str, PathLike, TextIO]] = None + ): + cls.REALTYPE_BY_DESC = cls.realtype_by_desc_from_dump_file(dump_file) + cls.Fid.load_from_dump_file()
+ + @classmethod +
[docs] def load_from_datfile( + cls, dat_file: Optional[Union[str, PathLike, BinaryIO]] = None + ): + cls.REALTYPE_BY_DESC = cls.realtype_by_desc_from_datfile(dat_file) + cls.Fid.load_from_dump_file()
+ + @classmethod +
[docs] def load(cls): + try: + cls.load_from_datfile() + except FileNotFoundError: + cls.load_from_dump_file()
+ + +KiwoomOpenApiPlusRealType.Fid.__outer_class__ = KiwoomOpenApiPlusRealType +KiwoomOpenApiPlusRealType.load() + + +
[docs]def main(): + KiwoomOpenApiPlusRealType.dump_realtype_by_desc()
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.html new file mode 100644 index 00000000..cda3230c --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.html @@ -0,0 +1,262 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager

+import collections
+import random
+import threading
+
+from typing import Collection, List, Optional, Union
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import (
+    KiwoomOpenApiPlusDispatchFunctions,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusScreenManager(Logging): + +
[docs] MAXIMUM_NUMBER_OF_SCREENS = 200
+ + def __init__(self, control: Optional[KiwoomOpenApiPlusDispatchFunctions] = None): + self._control = control + self._lock = threading.RLock() + self._occupied_screen_nos = collections.deque( + maxlen=self.MAXIMUM_NUMBER_OF_SCREENS + ) + self._borrow_count_by_screen_no = {} + + @staticmethod +
[docs] def number_to_screen_no(number: int) -> str: + return str(number).zfill(4)
+ + @staticmethod +
[docs] def screen_no_to_number(screen_no: str) -> int: + return int(screen_no)
+ +
[docs] def is_inuse(self, screen_no: str) -> bool: + return ( + screen_no is not None + and self.screen_no_to_number(screen_no) in self._occupied_screen_nos + )
+ +
[docs] def get_single_free_screen(self, exclude: Optional[Collection[str]] = None) -> str: + if exclude is None: + exclude = [] + else: + exclude = [self.screen_no_to_number(scrnno) for scrnno in exclude] + exclude = set(exclude) + with self._lock: + if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: + self.logger.warning( + "Requesting free screen, but already using maximum number of screens." + ) + screen_no = random.choice( + [ + i + for i in range(1, 10000) + if i not in self._occupied_screen_nos and i not in exclude + ] + ) + screen_no = self.number_to_screen_no(screen_no) + return screen_no
+ +
[docs] def get_multiple_free_screens(self, count: int) -> List[str]: + screens = [] + for _ in range(count): + screens.append(self.get_single_free_screen(exclude=screens)) + return screens
+ +
[docs] def get_free_screen(self, count: Optional[int] = None) -> Union[str, List[str]]: + if count is None: + return self.get_single_free_screen() + else: + return self.get_multiple_free_screens(count)
+ +
[docs] def borrow_screen( + self, screen_no: Optional[str] = None, reuse: bool = True, pop: bool = True + ) -> str: + with self._lock: + if screen_no is None or screen_no == "": + screen_no = self.get_single_free_screen() + if not reuse: + if self.is_inuse(screen_no): + raise KiwoomOpenApiPlusError( + "Borrowing screen %s, but it's already is use." % screen_no + ) + if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: + self.logger.warning( + "Borrowing a screen, but already using maximum number of screens." + ) + if pop: + oldest = self._occupied_screen_nos.popleft() + del self._borrow_count_by_screen_no[oldest] + self.logger.warning( + "Oldest screen %s popped.", + self.number_to_screen_no(oldest), + ) + else: + raise KiwoomOpenApiPlusError("Cannot allocate more screen") + screen_no_int = self.screen_no_to_number(screen_no) + if not self.is_inuse(screen_no): + self._occupied_screen_nos.append(screen_no_int) + self._borrow_count_by_screen_no[screen_no_int] = ( + self._borrow_count_by_screen_no.get(screen_no_int, 0) + 1 + ) + if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: + self.logger.warning("Maximum number of screens reached.") + return screen_no
+ +
[docs] def return_screen(self, screen_no: str) -> bool: + try: + with self._lock: + screen_no_int = self.screen_no_to_number(screen_no) + self._borrow_count_by_screen_no[screen_no_int] -= 1 + if self._borrow_count_by_screen_no[screen_no_int] == 0: + self._occupied_screen_nos.remove(screen_no_int) + del self._borrow_count_by_screen_no[screen_no_int] + return True + except (KeyError, ValueError): + self.logger.warning("Returned screen %s, but not found.", screen_no) + return False
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.html new file mode 100644 index 00000000..019f7034 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.html @@ -0,0 +1,234 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector

+from __future__ import annotations
+
+import inspect
+import threading
+
+from typing import Any, Callable, Generic, List, Optional, TypeVar
+
+try:
+    from typing import ParamSpec
+except ImportError:
+    from typing_extensions import ParamSpec
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import (
+    KiwoomOpenApiPlusEventHandlerSignature,
+)
+from koapy.compat.pyside2 import PYQT5, PYSIDE2, PythonQtError
+from koapy.compat.pyside2.QtAxContainer import QAxWidget
+from koapy.utils.logging.Logging import Logging
+
+
[docs]P = ParamSpec("P")
+
[docs]R = TypeVar("R")
+ + +
[docs]class KiwoomOpenApiPlusSignalConnector(Logging, Generic[P, R]): + def __init__(self, name: str): + super().__init__() + + self._name = name + self._lock = threading.RLock() + self._slots: List[Callable[P, R]] = [] + + self._signature = KiwoomOpenApiPlusEventHandlerSignature.from_name(self._name) + self._param_types = [ + (p.annotation) for p in self._signature.parameters.values() + ] + + if PYSIDE2: + self._signal = self._signature.to_pyside2_event_signal() + + self.__name__ = self._name + self.__signature__ = self._signature + +
[docs] def is_valid_slot(self, slot: Callable[..., Any]) -> bool: + slot_signature = inspect.signature(slot) + slot_types = [(p.annotation) for p in slot_signature.parameters.values()] + condition = len(self._param_types) == len( + slot_types + ) # currently only check parameter length + return condition
+ +
[docs] def connect_to(self, control: QAxWidget): + if PYSIDE2: + return control.connect(self._signal, self) + elif PYQT5: + return getattr(control, self._name).connect(self) + else: + raise PythonQtError("Unsupported Qt bindings")
+ +
[docs] def disconnect_from(self, control: QAxWidget): + if PYSIDE2: + return control.disconnect(self._signal, self) + elif PYQT5: + return getattr(control, self._name).disconnect(self) + else: + raise PythonQtError("Unsupported Qt bindings")
+ +
[docs] def connect(self, slot: Callable[..., Any]): + if not self.is_valid_slot(slot): + raise ValueError("Tried to connect invalid slot: %s" % slot) + with self._lock: + if slot not in self._slots: + self._slots.append(slot)
+ +
[docs] def disconnect(self, slot: Optional[Callable[..., Any]] = None): + with self._lock: + if slot is None: + self._slots.clear() + elif slot in self._slots: + self._slots.remove(slot) + else: + self.logger.warning("Tried to disconnect a slot that doesn't exist")
+ +
[docs] def call(self, *args: P.args, **kwargs: P.kwargs) -> R: + # make a copy in order to prevent modification during iteration problem + with self._lock: + slots = list(self._slots) + # use Thread with await/join for concurrency? + for slot in slots: + slot(*args, **kwargs)
+ + def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: + return self.call(*args, **kwargs)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.html new file mode 100644 index 00000000..881e3e1a --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.html @@ -0,0 +1,226 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature

+from inspect import Parameter, Signature
+from typing import Dict
+
+import pythoncom
+
+from koapy.compat.pyside2 import PYSIDE2
+
+if PYSIDE2:
+    from koapy.compat.pyside2.QtCore import SIGNAL
+
+try:
+    from types import NoneType
+except ImportError:
+
[docs] NoneType = type(None)
+ + +
[docs]class KiwoomOpenApiPlusSignature(Signature): + +
[docs] PYTHONTYPE_TO_QTTYPE = { + int: "int", + str: "const QString&", + }
+ +
[docs] COMTYPE_TO_PYTHONTYPE = { + pythoncom.VT_I4: int, + pythoncom.VT_BSTR: str, + pythoncom.VT_VARIANT: Parameter.empty, + pythoncom.VT_VOID: NoneType, + }
+ + def __init__( + self, + name: str, + parameters: Dict[str, Parameter] = None, + return_annotation=Signature.empty, + ): + self._name = name + super().__init__(parameters, return_annotation=return_annotation) + + @property +
[docs] def name(self) -> str: + return self._name
+ + @classmethod + def _pythontype_to_qttype(cls, typ): + return cls.PYTHONTYPE_TO_QTTYPE[typ] + +
[docs] def to_pyside2_function_prototype(self) -> str: + name = self._name + parameters = self.parameters + parameters = parameters.values() + parameters = [self._pythontype_to_qttype(p.annotation) for p in parameters] + prototype = "{}({})".format(name, ", ".join(parameters)) + return prototype
+ + if PYSIDE2: + + def to_pyside2_event_signal(self) -> str: + return SIGNAL(self.to_pyside2_function_prototype()) + + @classmethod + def _comtype_to_pythontype(cls, typ): + return cls.COMTYPE_TO_PYTHONTYPE.get(typ, Parameter.empty) + + @classmethod + def _from_entry(cls, name, entry): + arg_names = entry.names[1:] + arg_types = [typ[0] for typ in entry.desc[2]] + return_type = entry.desc[8][0] + parameters = [ + Parameter( + name=arg_name, + kind=Parameter.POSITIONAL_OR_KEYWORD, + annotation=cls._comtype_to_pythontype(arg_type), + ) + for arg_name, arg_type in zip(arg_names, arg_types) + ] + return_annotation = cls._comtype_to_pythontype(return_type) + signature = cls( + name=name, + parameters=parameters, + return_annotation=return_annotation, + ) + return signature
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.html new file mode 100644 index 00000000..277aedeb --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.html @@ -0,0 +1,612 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo

+from __future__ import annotations
+
+import contextlib
+import io
+import json
+import zipfile
+
+from os import PathLike
+from pathlib import Path
+from typing import Any, Dict, List, Optional, Sequence, TextIO, Union
+
+from koapy.config import debug, default_encoding
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.serialization import JsonSerializable
+
+
+
[docs]class KiwoomOpenApiPlusTrInfo(JsonSerializable, Logging): + +
[docs] TRINFO_BY_CODE_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata"
+
[docs] TRINFO_BY_CODE_DUMP_FILENAME = "trinfo_by_code.json"
+
[docs] TRINFO_BY_CODE_DUMP_FILEPATH = ( + TRINFO_BY_CODE_DUMP_FILEDIR / TRINFO_BY_CODE_DUMP_FILENAME + )
+ +
[docs] TRINFO_BY_CODE: Dict[str, KiwoomOpenApiPlusTrInfo] = {}
+ +
[docs] class Field(JsonSerializable): + + __outer_class__ = None + + def __init__( + self, + name: Optional[str] = None, + start: Optional[int] = None, + offset: Optional[int] = None, + fid: Optional[int] = None, + ): + self.name = name + self.start = start + self.offset = offset + self.fid = fid + + def __repr__(self): + return "{}.{}({!r}, {!r}, {!r}, {!r})".format( + self.__outer_class__.__name__, + self.__class__.__name__, + self.name, + self.start, + self.offset, + self.fid, + ) + + def __eq__(self, other): + if isinstance(other, type(self)): + return ( + self.name == other.name + and self.start == other.start + and self.offset == other.offset + and self.fid == other.fid + ) + return False
+ + def __init__( + self, + tr_code: Optional[str] = None, + name: Optional[str] = None, + tr_name: Optional[str] = None, + tr_names_svr: Optional[str] = None, + tr_type: Optional[str] = None, + gfid: Optional[str] = None, + inputs: Optional[Sequence[Field]] = None, + single_outputs_name: Optional[str] = None, + single_outputs: Optional[Sequence[Field]] = None, + multi_outputs_name: Optional[str] = None, + multi_outputs: Optional[Sequence[Field]] = None, + ): + self.tr_code = tr_code + self.name = name + self.tr_name = tr_name + self.tr_names_svr = tr_names_svr + self.tr_type = tr_type + self.gfid = gfid + self.inputs = inputs + self.single_outputs_name = single_outputs_name + self.single_outputs = single_outputs + self.multi_outputs_name = multi_outputs_name + self.multi_outputs = multi_outputs + + def __repr__(self): + return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format( + self.__class__.__name__, + self.tr_code, + self.name, + self.tr_name, + self.tr_names_svr, + self.tr_type, + self.gfid, + self.inputs, + self.single_outputs_name, + self.single_outputs, + self.multi_outputs_name, + self.multi_outputs, + ) + + def __eq__(self, other): + if isinstance(other, type(self)): + return ( + self.tr_code.lower() == other.tr_code.lower() + and self.name == other.name + and self.tr_name == other.tr_name + and self.tr_names_svr == other.tr_names_svr + and self.tr_type == other.tr_type + and self.gfid == other.gfid + and self.inputs == other.inputs + and self.single_outputs_name == other.single_outputs_name + and self.single_outputs == other.single_outputs + and self.multi_outputs_name == other.multi_outputs_name + and self.multi_outputs == other.multi_outputs + ) + return False + +
[docs] def to_dict(self) -> Dict[str, Any]: + dic = dict(self.__dict__) + for attr in dic: + if isinstance(dic[attr], list): + dic[attr] = [field.to_dict() for field in dic[attr]] + return dic
+ + @classmethod +
[docs] def from_dict(cls, dic: Dict[str, Any]) -> KiwoomOpenApiPlusTrInfo: + output = cls() + for name in output.__dict__: + value = dic.get(name) + if isinstance(value, list): + fields = [cls.Field.from_dict(d) for d in value] + setattr(output, name, fields) + else: + setattr(output, name, value) + return output
+ +
[docs] def get_input_names(self) -> List[str]: + return [input_.name for input_ in self.inputs]
+ +
[docs] def get_single_output_names(self) -> List[str]: + return [output.name for output in self.single_outputs]
+ +
[docs] def get_multi_output_names(self) -> List[str]: + return [output.name for output in self.multi_outputs]
+ + @classmethod +
[docs] def get_trcode_list(cls) -> List[str]: + return list(cls.TRINFO_BY_CODE.keys())
+ + @classmethod +
[docs] def get_trinfo_list(cls) -> List[KiwoomOpenApiPlusTrInfo]: + return list(cls.TRINFO_BY_CODE.values())
+ + @classmethod +
[docs] def get_trinfo_by_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo]: + return cls.TRINFO_BY_CODE.get(trcode.lower())
+ + @classmethod +
[docs] def from_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo]: + return cls.get_trinfo_by_code(trcode)
+ + @classmethod +
[docs] def from_encfile( + cls, + f: Union[str, PathLike, TextIO], + tr_code: Optional[str] = None, + encoding: Optional[str] = None, + ) -> KiwoomOpenApiPlusTrInfo: + with contextlib.ExitStack() as stack: + if isinstance(f, str): + f = Path(f) + if isinstance(f, PathLike): + filename = f + if encoding is None: + encoding = "euc-kr" + f = open(filename, "r", encoding=encoding) + f = stack.enter_context(f) + tr_code = filename.stem.lower() + elif tr_code is None: + raise ValueError("Argument tr_code should be given.") + + lines = iter(f) + lines = map(lambda line: line.rstrip("\n"), lines) + lines = filter(lambda line: len(line.strip()) > 0, lines) + + single_outputs_name = "" + single_outputs = [] + multi_outputs_name = "" + multi_outputs = [] + + tr_names_svr = "" + gfid = "" + + line = next(lines) + assert line == "[TRINFO]" + line = next(lines) + assert line.startswith("TRName=") + tr_name = line.split("=", 2)[1] + line = next(lines) + if line.startswith("TRNameSVR="): + tr_names_svr = line.split("=", 2)[1] + line = next(lines) + assert line.startswith("TRType=") + tr_type = line.split("=", 2)[1] + line = next(lines) + if line.startswith("GFID="): + gfid = line.split("=", 2)[1] + line = next(lines) + assert line == "[INPUT]" + line = next(lines) + assert line.startswith("@START_") + tr_name_readable = line.split("_", 2)[1].split("=", 2)[0] + line = next(lines) + inputs = [] + while not line.startswith("@END_"): + input_name, triple = [ + item.strip() for item in line.strip().split("=", 2) + ] + triple = [item.strip() for item in triple.split(",")] + start, offset, fid = [int(item) for item in triple] + inputs.append(cls.Field(input_name, start, offset, fid)) + line = next(lines) + line = next(lines) + assert line == "[OUTPUT]" + line = next(lines) + assert line.startswith("@START_") + single_outputs_name = line.split("_", 2)[1].split("=", 2)[0] + line = next(lines) + while not line.startswith("@END_"): + output_name, triple = [ + item.strip() for item in line.strip().split("=", 2) + ] + triple = [item.strip() for item in triple.split(",")] + start, offset, fid = [int(item) if item else 0 for item in triple] + single_outputs.append(cls.Field(output_name, start, offset, fid)) + line = next(lines) + try: + line = next(lines) + except StopIteration: + pass + else: + if line.startswith("@START_"): + multi_outputs_name = line.split("_", 2)[1].split("=", 2)[0] + line = next(lines) + while not line.startswith("@END_"): + output_name, triple = [ + item.strip() for item in line.strip().split("=", 2) + ] + triple = [item.strip() for item in triple.split(",")] + start, offset, fid = [ + int(item) if item else 0 for item in triple + ] + multi_outputs.append(cls.Field(output_name, start, offset, fid)) + line = next(lines) + return cls( + tr_code, + tr_name_readable, + tr_name, + tr_names_svr, + tr_type, + gfid, + inputs, + single_outputs_name, + single_outputs, + multi_outputs_name, + multi_outputs, + )
+ + @classmethod +
[docs] def infos_from_data_dir( + cls, + data_dir: Optional[Union[str, PathLike]] = None, + encoding: Optional[str] = None, + module_path: Optional[str] = None, + ) -> List[KiwoomOpenApiPlusTrInfo]: + if data_dir is None: + if module_path is None: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + module_path = API_MODULE_PATH + data_dir = module_path / "data" + + if isinstance(data_dir, str): + data_dir = Path(data_dir) + + if encoding is None: + encoding = "euc-kr" + + if debug: + cls.logger.debug("Reading files under %s", data_dir) + + enc_filenames = [filename.name.lower() for filename in data_dir.iterdir()] + enc_filenames = [ + filename + for filename in enc_filenames + if filename.startswith("o") and filename.endswith(".enc") + ] + results = [] + for filename in enc_filenames: + full_filename = data_dir / filename + with zipfile.ZipFile(full_filename) as z: + for info in z.infolist(): + inner_filename = info.filename + tr_code = Path(inner_filename).stem.lower() + if debug: + cls.logger.debug( + "Reading file %s inside %s", inner_filename, full_filename + ) + with z.open(info) as b: + with io.TextIOWrapper(b, encoding=encoding) as f: + results.append(cls.from_encfile(f, tr_code)) + return results
+ +
[docs] SINGLE_TO_MULTI_TRCODES = [ + "opt10072", + "opt10073", + "opt10075", + "opt10076", + "opt10085", + "optkwfid", + "optkwinv", + "optkwpro", + ]
+ + @classmethod +
[docs] def swap_output_types( + cls, item: KiwoomOpenApiPlusTrInfo + ) -> KiwoomOpenApiPlusTrInfo: + multi_outputs_name = item.multi_outputs_name + multi_outputs = item.multi_outputs + item.multi_outputs_name = item.single_outputs_name + item.multi_outputs = item.single_outputs + item.single_outputs_name = multi_outputs_name + item.single_outputs = multi_outputs + return item
+ + @classmethod +
[docs] def trinfo_by_code_from_data_dir( + cls, data_dir: Optional[Union[str, PathLike]] = None, post_process: bool = True + ) -> Dict[str, KiwoomOpenApiPlusTrInfo]: + infos = cls.infos_from_data_dir(data_dir) + result = {info.tr_code: info for info in infos} + if post_process: + for tr_code in result: + if tr_code in cls.SINGLE_TO_MULTI_TRCODES: + item = result[tr_code] + item = cls.swap_output_types(item) + result[tr_code] = item + return result
+ + @classmethod +
[docs] def dump_trinfo_by_code( + cls, + dump_file: Optional[Union[str, PathLike, TextIO]] = None, + data_dir: Optional[str] = None, + encoding: Optional[str] = None, + ): + if dump_file is None: + dump_file = cls.TRINFO_BY_CODE_DUMP_FILEPATH + with contextlib.ExitStack() as stack: + if isinstance(dump_file, str): + dump_file = Path(dump_file) + if isinstance(dump_file, PathLike): + dump_filename = dump_file + if encoding is None: + encoding = default_encoding + dump_file = open(dump_file, "w", encoding=encoding) + dump_file = stack.enter_context(dump_file) + else: + dump_filename = None + result = cls.trinfo_by_code_from_data_dir(data_dir) + for tr_code in result: + result[tr_code] = result[tr_code].to_dict() + if dump_filename is not None: + cls.logger.debug("Saving trinfo to %s", dump_filename) + return json.dump( + result, + dump_file, + indent=4, + sort_keys=True, + ensure_ascii=False, + )
+ + @classmethod +
[docs] def trinfo_by_code_from_dump_file( + cls, + dump_file: Optional[Union[str, PathLike, TextIO]] = None, + encoding: Optional[str] = None, + ) -> Dict[str, KiwoomOpenApiPlusTrInfo]: + if dump_file is None: + dump_file = cls.TRINFO_BY_CODE_DUMP_FILEPATH + with contextlib.ExitStack() as stack: + if isinstance(dump_file, str): + dump_file = Path(dump_file) + if isinstance(dump_file, PathLike): + if dump_file.exists() and dump_file.stat().st_size > 0: + if encoding is None: + encoding = default_encoding + dump_file = open(dump_file, "r", encoding=encoding) + dump_file = stack.enter_context(dump_file) + else: + return {} + result = json.load(dump_file) + for tr_code in result: + item = cls.from_dict(result[tr_code]) + result[tr_code] = item + return result
+ + @classmethod +
[docs] def load_from_dump_file( + cls, dump_file: Optional[Union[str, PathLike, TextIO]] = None + ): + cls.TRINFO_BY_CODE = cls.trinfo_by_code_from_dump_file(dump_file)
+ + @classmethod +
[docs] def load_from_data_dir(cls, data_dir: Optional[Union[str, PathLike]] = None): + cls.TRINFO_BY_CODE = cls.trinfo_by_code_from_data_dir(data_dir)
+ + @classmethod +
[docs] def load(cls): + try: + cls.load_from_data_dir() + except FileNotFoundError: + cls.load_from_dump_file()
+ + +KiwoomOpenApiPlusTrInfo.Field.__outer_class__ = KiwoomOpenApiPlusTrInfo +KiwoomOpenApiPlusTrInfo.load() + + +
[docs]def main(): + KiwoomOpenApiPlusTrInfo.dump_trinfo_by_code()
+ + +
[docs]def infer_fids_by_tr_outputs(output_filename=None): + if output_filename is None: + output_filename = "fid.xlsx" + infos = KiwoomOpenApiPlusTrInfo.infos_from_data_dir() + fields = [] + for info in infos: + for field in info.single_outputs: + fields.append(field) + for field in info.multi_outputs: + fields.append(field) + pairs = [[field.fid, field.name] for field in fields if field.fid != -1] + import string # pylint: disable=import-outside-toplevel + + for pair in pairs: + if pair[1].startswith("풋_"): + pair[1] = pair[1][2:] + if not pair[1][0] in string.ascii_letters and pair[1][-1] in "ns": + pair[1] = pair[1][:-1] + pair[1] = pair[1].upper() + pairs = [tuple(pair) for pair in pairs] + pairs = list(set(pairs)) + pairs = sorted(pairs, key=lambda item: item[0]) + import pandas as pd # pylint: disable=import-outside-toplevel + + df = pd.DataFrame.from_records(pairs) + df.to_excel(output_filename, header=False, index=False)
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.html new file mode 100644 index 00000000..679195a5 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.html @@ -0,0 +1,155 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import (
+    DISPATCH_CLSID,
+    EVENT_CLSID,
+    TYPELIB_SPEC,
+)
+from koapy.utils.pywin32 import BuildOleItems, LoadTypeLib
+
+
[docs]TYPELIB = LoadTypeLib(TYPELIB_SPEC)
+ +OLE_ITEMS, ENUM_ITEMS, RECORD_ITEMS, VTABLE_ITEMS = BuildOleItems(TYPELIB_SPEC, TYPELIB) + +
[docs]DISPATCH_OLE_ITEM = OLE_ITEMS.get(DISPATCH_CLSID)
+
[docs]EVENT_OLE_ITEM = OLE_ITEMS.get(EVENT_CLSID)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.html new file mode 100644 index 00000000..29b8dcba --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.html @@ -0,0 +1,165 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec

+from pathlib import Path
+
+from pywintypes import IID
+
+from koapy.utils.pywin32 import GetLatestTypelibSpec, GetTypelibSpecs
+
+
[docs]CONTROL_PROGID = "KHOPENAPI.KHOpenApiCtrl.1"
+ +
[docs]CONTROL_CLSID = IID("{A1574A0D-6BFA-4BD7-9020-DED88711818D}")
+
[docs]DISPATCH_CLSID = IID("{CF20FBB6-EDD4-4BE5-A473-FEF91977DEB6}")
+
[docs]EVENT_CLSID = IID("{7335F12D-8973-4BD5-B7F0-12DF03D175B7}")
+
[docs]MODULE_CLSID = IID("{6D8C2B4D-EF41-4750-8AD4-C299033833FB}")
+ +
[docs]TYPELIB_SPECS = GetTypelibSpecs(MODULE_CLSID)
+
[docs]TYPELIB_SPEC = GetLatestTypelibSpec(TYPELIB_SPECS)
+ +
[docs]TYPELIB_DLL_PATH = TYPELIB_SPEC and TYPELIB_SPEC.dll and Path(TYPELIB_SPEC.dll)
+ +
[docs]API_MODULE_PATH_FROM_DEFAULT_INSTALLATION = Path("C:\\OpenAPI")
+
[docs]API_MODULE_PATH_FROM_TYPELIB_DLL = TYPELIB_DLL_PATH and TYPELIB_DLL_PATH.parent
+
[docs]API_MODULE_PATH = ( + API_MODULE_PATH_FROM_TYPELIB_DLL or API_MODULE_PATH_FROM_DEFAULT_INSTALLATION +)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.html new file mode 100644 index 00000000..d796b0fa --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.html @@ -0,0 +1,367 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater

+import os
+import subprocess
+import sys
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import (
+    KiwoomOpenApiPlusQAxWidgetMixin,
+)
+from koapy.utils.ctypes import is_admin
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.platform import is_32bit
+from koapy.utils.subprocess import Popen, function_to_subprocess_args
+
+
+
[docs]class KiwoomOpenApiPlusVersionUpdater(Logging): + def __init__(self, credentials): + self._credentials = credentials + +
[docs] def get_api_module_path(self): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + module_path = API_MODULE_PATH + return module_path
+ +
[docs] def get_autologin_dat(self): + module_path = self.get_api_module_path() + autologin_dat = module_path / "system" / "Autologin.dat" + return autologin_dat
+ +
[docs] def is_autologin_enabled(self): + autologin_dat = self.get_autologin_dat() + return autologin_dat.exists()
+ +
[docs] def disable_autologin(self): + self.logger.info("Disabling auto login") + autologin_dat = self.get_autologin_dat() + if autologin_dat.exists(): + self.logger.info("Removing %s", autologin_dat) + os.remove(autologin_dat) + self.logger.info("Disabled auto login") + return True + else: + self.logger.info("Autologin is already disabled") + return False
+ + @classmethod +
[docs] def open_login_window_impl(cls): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( + KiwoomOpenApiPlusError, + ) + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( + KiwoomOpenApiPlusQAxWidget, + ) + from koapy.compat.pyside2.QtWidgets import QApplication + + cls.logger.info("Opening login window") + app = QApplication(sys.argv) + control = KiwoomOpenApiPlusQAxWidget() + if control.GetConnectState() == 0: + + def OnEventConnect(errcode): + control.OnEventConnect.disconnect(OnEventConnect) + KiwoomOpenApiPlusError.try_or_raise(errcode) + app.exit(errcode) + + control.OnEventConnect.connect(OnEventConnect) + KiwoomOpenApiPlusError.try_or_raise(control.CommConnect()) + return app.exec_()
+ +
[docs] def open_login_window(self): + # opening login window is a blocking process. (`app.exec_()` is the blocking process and will wait for `app.exit()`) + # also it's hard to use both PySide2/PyQt5 and pywinauto at the same time in the same process due to compatibility issue. + # + # in order to avoid the issues mentioned above we are creating login window in a separate process. + # and then will do login using pywinauto in another process using `login_using_pywinauto()` function. + # + # this process will stay alive until `OnEventConnect` event happens, hopefully a successful login. + # + # for more information about the compatibility issue between PySide2/PyQt5 and pywinauto, check the following link: + # https://github.com/pywinauto/pywinauto/issues/472 + + def main(): + # pylint: disable=redefined-outer-name,import-self + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( + KiwoomOpenApiPlusVersionUpdater, + ) + + KiwoomOpenApiPlusVersionUpdater.open_login_window_impl() + + cmd = function_to_subprocess_args(main) + creationflags = subprocess.CREATE_NEW_PROCESS_GROUP + proc = Popen(cmd, creationflags=creationflags) + return proc
+ + @classmethod +
[docs] def show_account_window_impl(cls): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( + KiwoomOpenApiPlusError, + ) + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( + KiwoomOpenApiPlusQAxWidget, + ) + from koapy.compat.pyside2.QtWidgets import QApplication + + cls.logger.info("Showing account window") + app = QApplication(sys.argv) + control = KiwoomOpenApiPlusQAxWidget() + if control.GetConnectState() == 0: + + def OnEventConnect(errcode): + control.OnEventConnect.disconnect(OnEventConnect) + KiwoomOpenApiPlusError.try_or_raise(errcode) + control.KOA_Functions("ShowAccountWindow", "") + app.exit(errcode) + + control.OnEventConnect.connect(OnEventConnect) + KiwoomOpenApiPlusError.try_or_raise(control.CommConnect()) + return app.exec_()
+ +
[docs] def show_account_window(self): + # this function does pretty much the same job like the `open_login_window()` function. + # but the difference is that it will show up the account setting window after successful login, + # so that we can (re-)enable the auto login functionality provided by the OpenAPI itself. + # + # this process will stay live until the account window is closed in the `OnEventConnect` event, + # hopefully after successfully enabling the auto login functionality. + # + # note that the `control.KOA_Functions('ShowAccountWindow', '')` line is also blocking process. + # so it will block until the account window is closed after enabling the auto login. + + def main(): + # pylint: disable=redefined-outer-name,import-self + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( + KiwoomOpenApiPlusVersionUpdater, + ) + + KiwoomOpenApiPlusVersionUpdater.show_account_window_impl() + + cmd = function_to_subprocess_args(main) + creationflags = subprocess.CREATE_NEW_PROCESS_GROUP + proc = Popen(cmd, creationflags=creationflags) + return proc
+ + @classmethod +
[docs] def check_apply_simulation_window(cls): + import pywinauto + + desktop = pywinauto.Desktop(allow_magic_lookup=False) + apply_simulation_window = desktop.window(title="모의투자 참가신청") + + try: + timeout_apply_simulation = 5 + apply_simulation_window.wait("ready", timeout_apply_simulation) + except pywinauto.timings.TimeoutError: + pass + else: + cls.logger.warning("Please apply for simulation server before using it") + raise RuntimeError("Please apply for simulation server before using it")
+ + @classmethod +
[docs] def login_using_pywinauto(cls, credentials): + # reusing the implementation in the mixin + KiwoomOpenApiPlusQAxWidgetMixin.LoginUsingPywinauto_Impl(credentials) + cls.check_apply_simulation_window()
+ + @classmethod +
[docs] def enable_autologin_using_pywinauto(cls, credentials): + # reusing the implementation in the mixin + account_passwords = credentials.get("account_passwords") + KiwoomOpenApiPlusQAxWidgetMixin.EnableAutoLoginUsingPywinauto_Impl( + account_passwords + )
+ +
[docs] def enable_autologin(self): + self.logger.info("Start enabling auto login") + + # pylint: disable=unused-variable + account_window_proc = self.show_account_window() + + credentials = self._credentials + + self.login_using_pywinauto(credentials) + self.enable_autologin_using_pywinauto(credentials)
+ + @classmethod +
[docs] def handle_version_upgrade_using_pywinauto(cls, pid): + return KiwoomOpenApiPlusQAxWidgetMixin.HandleVersionUpgradeUsingPywinauto_Impl( + pid + )
+ +
[docs] def try_version_update_using_pywinauto(self): + self.logger.info("Trying version update") + + is_autologin_enabled = self.is_autologin_enabled() + + if is_autologin_enabled: + self.disable_autologin() + + login_window_proc = self.open_login_window() + + credentials = self._credentials + + self.login_using_pywinauto(credentials) + + is_updated = self.handle_version_upgrade_using_pywinauto(login_window_proc.pid) + + if is_autologin_enabled: + self.logger.info("Enabling auto login back") + self.enable_autologin() + if is_updated: + self.logger.info("Done update, enabled auto login") + else: + self.logger.info("There was no version update, enabled auto login") + + return is_updated
+ +
[docs] def update_version_if_necessary(self): + assert ( + is_32bit() + ), "Automatic version update requires to be run in 32bit environment" + assert ( + is_admin() + ), "Automatic version update requires to be run as administrator" + return self.try_version_update_using_pywinauto()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.html b/_modules/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.html new file mode 100644 index 00000000..aae17c1d --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.html @@ -0,0 +1,263 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs

+import ast
+
+from pathlib import Path
+
+import pythoncom
+
+from koapy.config import default_encoding
+
+try:
+    from ast import unparse
+except ImportError:
+    from astunparse import unparse
+
+
+
[docs]def generate_python_stubs( + dispatch_class_name=None, + dispatch_file_path=None, + event_class_name=None, + event_file_path=None, + encoding=None, + force_overwrite=False, +): + if dispatch_class_name is None: + dispatch_class_name = "KiwoomOpenApiPlusDispatchFunctionsGenerated" + if dispatch_file_path is None: + dispatch_file_path = dispatch_class_name + ".py" + + if event_class_name is None: + event_class_name = "KiwoomOpenApiPlusEventFunctionsGenerated" + if event_file_path is None: + event_file_path = event_class_name + ".py" + + if encoding is None: + encoding = default_encoding + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( + DISPATCH_OLE_ITEM, + EVENT_OLE_ITEM, + ) + + dispatch_item = DISPATCH_OLE_ITEM + event_item = EVENT_OLE_ITEM + + ellipsis_function_body = [ast.Expr(ast.Constant(Ellipsis))] + comtype_to_annotation = { + pythoncom.VT_I4: int.__name__, + pythoncom.VT_BSTR: str.__name__, + pythoncom.VT_VARIANT: str(None), + pythoncom.VT_VOID: str(None), + } + + dispatch_func_defs = [] + for _name, entry in dispatch_item.mapFuncs.items(): + func_name = entry.names[0] + arg_names = entry.names[1:] + arg_descs = entry.desc.args + args = [ast.arg("self", None)] + for arg_name, (arg_type, _arg_flag, _arg_default, _arg_crap) in zip( + arg_names, arg_descs + ): + arg_type = comtype_to_annotation[arg_type] + arg_annotation = ast.Name(arg_type, ast.Load()) + arg = ast.arg(arg_name, arg_annotation) + arg.lineno = None + arg.col_offset = None + args.append(arg) + args = ast.arguments([], args, None, [], [], None, []) + return_type = entry.desc.rettype[0] + return_type = comtype_to_annotation[return_type] + returns = ast.Name(return_type, ast.Load()) + func_def = ast.FunctionDef(func_name, args, ellipsis_function_body, [], returns) + func_def.lineno = None + func_def.col_offset = None + dispatch_func_defs.append(func_def) + dispatch_class_def = ast.ClassDef( + dispatch_class_name, [], [], dispatch_func_defs, [] + ) + + event_func_defs = [] + for _name, entry in event_item.mapFuncs.items(): + func_name = entry.names[0] + arg_names = entry.names[1:] + arg_descs = entry.desc.args + args = [ast.arg("self", None)] + for arg_name, (arg_type, _arg_flag, _arg_default, _arg_crap) in zip( + arg_names, arg_descs + ): + arg_type = comtype_to_annotation[arg_type] + arg_annotation = ast.Name(arg_type, ast.Load()) + arg = ast.arg(arg_name, arg_annotation) + arg.lineno = None + arg.col_offset = None + args.append(arg) + args = ast.arguments([], args, None, [], [], None, []) + return_type = entry.desc.rettype[0] + return_type = comtype_to_annotation[return_type] + returns = ast.Name(return_type, ast.Load()) + func_def = ast.FunctionDef(func_name, args, ellipsis_function_body, [], returns) + func_def.lineno = None + func_def.col_offset = None + event_func_defs.append(func_def) + + event_class_def = ast.ClassDef(event_class_name, [], [], event_func_defs, []) + + dispatch_file_path = Path(dispatch_file_path) + if not dispatch_file_path.exists() or force_overwrite: + with open(dispatch_file_path, "w", encoding=encoding) as f: + mod = ast.Module([dispatch_class_def], []) + code = unparse(mod) + f.write(code) + + event_file_path = Path(event_file_path) + if not event_file_path.exists() or force_overwrite: + with open(event_file_path, "w", encoding=encoding) as f: + mod = ast.Module([event_class_def], []) + code = unparse(mod) + f.write(code)
+ + +if __name__ == "__main__": + generate_python_stubs() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.html new file mode 100644 index 00000000..368dfe72 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.html @@ -0,0 +1,272 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient

+import inspect
+
+from concurrent.futures import ThreadPoolExecutor
+
+import grpc
+
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2_grpc
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper import (
+    KiwoomOpenApiPlusServiceClientStubWrapper,
+)
+from koapy.config import config
+
+
+
[docs]class KiwoomOpenApiPlusServiceClient: + def __init__( + self, + host=None, + port=None, + credentials=None, + thread_pool=None, + check_timeout=None, + **kwargs, + ): + if host is None: + host = config.get_string( + "koapy.backend.kiwoom_open_api_plus.grpc.host", "localhost" + ) + host = config.get_string( + "koapy.backend.kiwoom_open_api_plus.grpc.client.host", host + ) + if port is None: + port = config.get_int("koapy.backend.kiwoom_open_api_plus.grpc.port") + port = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.client.port", port + ) + + if check_timeout is None: + check_timeout = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.client.is_ready.timeout", 10 + ) + + self._host = host + self._port = port + self._credentials = credentials + self._thread_pool = thread_pool + self._check_timeout = check_timeout + self._kwargs = kwargs + + self._target = self._host + ":" + str(self._port) + + if self._credentials is None: + channel_signature = inspect.signature(grpc.insecure_channel) + channel_params = list(channel_signature.parameters.keys()) + channel_kwargs = { + k: v for k, v in self._kwargs.items() if k in channel_params + } + channel_bound_arguments = channel_signature.bind_partial(**channel_kwargs) + channel_bound_arguments.arguments["target"] = self._target + self._channel = grpc.insecure_channel( + *channel_bound_arguments.args, + **channel_bound_arguments.kwargs, + ) + else: + channel_signature = inspect.signature(grpc.secure_channel) + channel_params = list(channel_signature.parameters.keys()) + channel_kwargs = { + k: v for k, v in self._kwargs.items() if k in channel_params + } + channel_bound_arguments = channel_signature.bind_partial(**channel_kwargs) + channel_bound_arguments.arguments["target"] = self._target + channel_bound_arguments.arguments["credentials"] = self._credentials + self._channel = grpc.secure_channel( + *channel_bound_arguments.args, + **channel_bound_arguments.kwargs, + ) + + if self._thread_pool is None: + thread_pool_signature = inspect.signature(ThreadPoolExecutor) + thread_pool_params = list(thread_pool_signature.parameters.keys()) + thread_pool_kwargs = { + k: v for k, v in self._kwargs.items() if k in thread_pool_params + } + thread_pool_bound_arguments = thread_pool_signature.bind( + **thread_pool_kwargs + ) + if thread_pool_bound_arguments.arguments.get("max_workers") is None: + max_workers = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.client.max_workers", + 8, + ) + thread_pool_bound_arguments.arguments["max_workers"] = max_workers + self._thread_pool = ThreadPoolExecutor( + *thread_pool_bound_arguments.args, + **thread_pool_bound_arguments.kwargs, + ) + + self._stub = KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceStub( + self._channel + ) + self._stub_wrapped = KiwoomOpenApiPlusServiceClientStubWrapper( + self._stub, self._thread_pool + ) + +
[docs] def is_ready(self, timeout=None): + if timeout is None: + timeout = self._check_timeout + try: + grpc.channel_ready_future(self._channel).result(timeout=timeout) + return True + except grpc.FutureTimeoutError: + return False
+ +
[docs] def get_grpc_stub(self): + return self._stub
+ +
[docs] def get_stub(self): + return self._stub_wrapped
+ +
[docs] def close(self): + return self._channel.close()
+ + def __getattr__(self, name): + return getattr(self._stub_wrapped, name) + + def __enter__(self): + assert self.is_ready(), "Client is not ready" + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.html new file mode 100644 index 00000000..c3c73c99 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.html @@ -0,0 +1,178 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable

+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import (
+    convert_arguments_from_python_to_protobuf,
+)
+
+
+
[docs]class KiwoomOpenApiPlusServiceClientSideDynamicCallable: + def __init__(self, stub, name): + self._stub = stub + self._name = name + + @classmethod + def _create_call_request(cls, name, args): + request = KiwoomOpenApiPlusService_pb2.CallRequest() + request.name = name + convert_arguments_from_python_to_protobuf( + args, request.arguments + ) # pylint: disable=no-member + return request + + @classmethod + def _unpack_response(cls, response): + if response.return_value.HasField("string_value"): + return response.return_value.string_value + elif response.return_value.HasField("bool_value"): + return response.return_value.bool_value + elif response.return_value.HasField("long_value"): + return response.return_value.long_value + else: + return None + + def __call__(self, *args): + request = self._create_call_request(self._name, args) + response = self._stub.Call(request) + result = self._unpack_response(response) + return result
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.html new file mode 100644 index 00000000..9c305418 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.html @@ -0,0 +1,220 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector

+import atexit
+import threading
+import time
+
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import (
+    convert_arguments_from_protobuf_to_python,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import (
+    QueueBasedIterableObserver,
+)
+
+
+
[docs]class KiwoomOpenApiPlusServiceClientSideSignalConnector: + def __init__(self, stub, name, executor): + self._stub = stub + self._name = name + self._executor = executor + self._lock = threading.RLock() + self._observers = {} + + atexit.register(self.shutdown) + + def __del__(self): + atexit.unregister(self.shutdown) + + def _stop_observer(self, observer): + request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() + request.stop_listen_request.time = time.time() + observer.on_next(request) + observer.on_completed() + + def _get_observer(self, callback, default=None): + return self._observers.setdefault(self._name, {}).get(callback, default) + + def _remove_observer(self, callback): + with self._lock: + observer = self._get_observer(callback) + if observer: + self._stop_observer(observer) + del self._observers[self._name][callback] + return observer + + def _add_observer(self, callback): + with self._lock: + self._remove_observer(callback) + observer = QueueBasedIterableObserver() + self._observers[self._name][callback] = observer + return observer + +
[docs] def shutdown(self): + with self._lock: + for _name, observers in self._observers.items(): + for _callback, observer in observers.items(): + self._stop_observer(observer)
+ +
[docs] def connect(self, callback): + with self._lock: + observer = self._add_observer(callback) + + def fn(): + request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() + request.listen_request.slots.append(self._name) + observer.on_next(request) + observer_iterator = iter(observer) + response_iterator = self._stub.BidirectionalListen(observer_iterator) + for response in response_iterator: + args = convert_arguments_from_protobuf_to_python(response.arguments) + callback(*args) + request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() + request.handled_request.time = time.time() + observer.on_next(request) + + _future = self._executor.submit(fn)
+ +
[docs] def disconnect(self, callback): + with self._lock: + self._remove_observer(callback)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.html new file mode 100644 index 00000000..7147afdb --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.html @@ -0,0 +1,1602 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper

+import datetime
+import logging
+import re
+
+import pandas as pd
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import (
+    KiwoomOpenApiPlusDispatchSignature,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import (
+    KiwoomOpenApiPlusEventHandlerSignature,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import (
+    KiwoomOpenApiPlusQAxWidgetUniversalMixin,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable import (
+    KiwoomOpenApiPlusServiceClientSideDynamicCallable,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector import (
+    KiwoomOpenApiPlusServiceClientSideSignalConnector,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous import (
+    PipeableMultiThreadedRendezvous,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusServiceClientStubCoreWrapper( + KiwoomOpenApiPlusQAxWidgetUniversalMixin +): + """ + KiwoomOpenApiPlusServiceServicer 에서 구현되어 이후 Stub 을 통해 제공되는 + RPC 들을 클라이언트에서 좀 더 쉽게 사용하기 위한 래퍼 함수들을 제공합니다. + """ + +
[docs] METHOD_NAMES = KiwoomOpenApiPlusDispatchSignature.names()
+
[docs] EVENT_NAMES = KiwoomOpenApiPlusEventHandlerSignature.names()
+ + def __init__(self, stub, executor): + self._stub = stub + self._executor = executor + + # Set methods as attributes + for method_name in self.METHOD_NAMES: + dynamic_callable = KiwoomOpenApiPlusServiceClientSideDynamicCallable( + self._stub, method_name + ) + setattr(self, method_name, dynamic_callable) + + # Set signals as attributes + for event_name in self.EVENT_NAMES: + signal_connector = KiwoomOpenApiPlusServiceClientSideSignalConnector( + self._stub, event_name, self._executor + ) + setattr(self, event_name, signal_connector) + + def __getattr__(self, name): + return getattr(self._stub, name) + +
[docs] def Call(self, name, *args): + """ + 임의의 함수 호출을 위한 RPC 입니다. + + 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 + 호출결과를 응답 메시지를 통해 전달합니다. + + 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. + """ + return KiwoomOpenApiPlusServiceClientSideDynamicCallable(self._stub, name)( + *args + )
+ +
[docs] def LoginCall(self, credentials=None): + """ + 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. + + CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + request = KiwoomOpenApiPlusService_pb2.LoginRequest() + if credentials is not None: + request.credentials.user_id = credentials.get("user_id") + request.credentials.user_password = credentials.get("user_password") + request.credentials.cert_password = credentials.get("cert_password") + request.credentials.is_simulation = credentials.get("is_simulation") + account_passwords = credentials.get("account_passwords") + for account_no, account_password in account_passwords.items(): + request.credentials.account_passwords[account_no] = account_password + for response in self._stub.LoginCall(request): + errcode = response.arguments[0].long_value + return errcode
+ +
[docs] def TransactionCall(self, rqname, trcode, scrno, inputs, stop_condition=None): + """ + TR 요청에 해당하는 RPC 입니다. + + CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. + + 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 + 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. + + 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 + 내부적으로 호출됩니다. + + 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 + 대기시간이 발생할 수 있습니다. + + 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. + 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, + TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. + """ + request = KiwoomOpenApiPlusService_pb2.TransactionRequest() + request.request_name = rqname + request.transaction_code = trcode + request.screen_no = scrno or "" + for k, v in inputs.items(): + request.inputs[k] = v + if stop_condition: + request.stop_condition.name = stop_condition.get("name", "") + request.stop_condition.value = str(stop_condition.get("value", "")) + request.stop_condition.comparator = { + "<=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO, + "<": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN, + ">=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO, + ">": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN, + "==": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO, + "!=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO, + }.get(stop_condition.get("comparator", "<=")) + return self._stub.TransactionCall(request)
+ +
[docs] def OrderCall( + self, + rqname, + scrno, + account, + order_type, + code, + quantity, + price, + quote_type, + original_order_no=None, + ): + """ + 주문 요청에 해당하는 RPC 입니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 + 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. + + 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. + 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. + + 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. + + 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 주문 유형: + - 1: 신규매수 + - 2: 신규매도 + - 3: 매수취소 + - 4: 매도취소 + - 5: 매수정정 + - 6: 매도정정 + + Args: + rqname (str): 사용자 구분 요청명 + scrno (str): 화면번호 (4자리) + account (str): 계좌번호 (10자리) + order_type (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + code (str): 종목코드 (6자리) + quantity (int): 주문수량 + price (int): 주문단가 + quote_type (str): 거래구분 (혹은 호가구분) + original_order_no (str): 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. + """ + request = KiwoomOpenApiPlusService_pb2.OrderRequest() + request.request_name = rqname or "" + request.screen_no = str(scrno).zfill(4) if scrno else "" + request.account_no = str(account) if account else "" + request.order_type = int(order_type) if order_type else 0 + request.code = code or "" + request.quantity = int(quantity) if quantity else 0 + request.price = int(price) if price else 0 + request.quote_type = quote_type or "" + request.original_order_no = original_order_no or "" + return self._stub.OrderCall(request)
+ +
[docs] def RealCall( + self, + scrno, + codes, + fids, + opt_type=None, + infer_fids=False, + readable_names=False, + fast_parse=False, + ): + """ + 실시간 데이터 요청에 해당하는 RPC 입니다. + + SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 + 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. + + 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 + 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. + 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. + """ + request = KiwoomOpenApiPlusService_pb2.RealRequest() + if scrno is None: + scrnos = [] + elif isinstance(scrno, str): + scrnos = [scrno] + else: + scrnos = scrno + fids = [int(fid) for fid in fids] + if opt_type is None: + opt_type = "0" + request.screen_no.extend(scrnos) + request.code_list.extend(codes) + request.fid_list.extend(fids) + request.opt_type = opt_type + request.flags.infer_fids = infer_fids + request.flags.readable_names = readable_names + request.flags.fast_parse = fast_parse + return self._stub.RealCall(request)
+ +
[docs] def LoadConditionCall(self): + """ + 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. + + GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + request = KiwoomOpenApiPlusService_pb2.LoadConditionRequest() + for response in self._stub.LoadConditionCall(request): + ret = response.arguments[0].long_value + msg = response.arguments[1].string_value + return (ret, msg)
+ +
[docs] def ConditionCall( + self, + scrno, + condition_name, + condition_index, + search_type, + with_info=False, + is_future_option=False, + request_name=None, + ): + """ + 조건검색 기능에 해당하는 RPC 입니다. + + SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 + 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + request = request = KiwoomOpenApiPlusService_pb2.ConditionRequest() + request.screen_no = scrno or "" + request.condition_name = condition_name + request.condition_index = condition_index + request.search_type = search_type + request.flags.with_info = with_info + request.flags.is_future_option = is_future_option + if request_name is not None: + request.request_name = request_name + return self._stub.ConditionCall(request)
+ +
[docs] def SetLogLevel(self, level, logger=""): + """ + 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. + """ + request = KiwoomOpenApiPlusService_pb2.SetLogLevelRequest() + request.level = level + request.logger = logger + return self._stub.SetLogLevel(request)
+ + def _LoadConditionUsingCall(self): + return self.Call("LoadCondition") + +
[docs] def LoadCondition(self): + """ + 조건검색 관련 조건식을 불러옵니다. + """ + return self._LoadConditionUsingCall()
+ + def _IsConditionLoadedUsingCall(self): + return self.Call("IsConditionLoaded") + +
[docs] def IsConditionLoaded(self): + """ + 조건식이 로드 되었는지 여부를 반환합니다. + """ + return self._IsConditionLoadedUsingCall()
+ + def _EnsureConditionLoadedUsingCall(self, force=False): + return self.Call("EnsureConditionLoaded", force) + +
[docs] def EnsureConditionLoaded(self, force=False): + """ + 조건식이 로드됨을 보장하도록 합니다. + + 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. + 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. + """ + return self._EnsureConditionLoadedUsingCall(force)
+ + def _RateLimitedCommRqDataUsingCall( + self, rqname, trcode, prevnext, scrno, inputs=None + ): + return self.Call( + "RateLimitedCommRqData", rqname, trcode, prevnext, scrno, inputs + ) + +
[docs] def RateLimitedCommRqData(self, rqname, trcode, prevnext, scrno, inputs=None): + """ + CommRqData() 와 동일하지만 호출제한 회피를 위한 함수입니다. + 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. + """ + self._RateLimitedCommRqDataUsingCall(rqname, trcode, prevnext, scrno, inputs)
+ + def _RateLimitedSendConditionUsingCall( + self, scrno, condition_name, condition_index, search_type + ): + return self.Call( + "RateLimitedSendCondition", + scrno, + condition_name, + condition_index, + search_type, + ) + +
[docs] def RateLimitedSendCondition( + self, scrno, condition_name, condition_index, search_type + ): + """ + SendCondition() 과 동일하지만 호출제한 회피를 위한 함수입니다. + 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. + """ + return self._RateLimitedSendConditionUsingCall( + scrno, condition_name, condition_index, search_type + )
+ + +
[docs]class KiwoomOpenApiPlusServiceClientStubExtendedWrapper( + KiwoomOpenApiPlusServiceClientStubCoreWrapper, Logging +): + """ + 제공되는 RPC 들을 활용한 여러 사용 케이스들을 구현합니다. + """ + + def _RemoveLeadingZerosForNumber(self, value, width=0): + remove = False + if width is None: + remove = False + elif isinstance(width, int) and (width == 0 or len(value) == width): + remove = True + elif hasattr(width, "__contains__") and len(value) in width: + remove = True + if remove: + return re.sub(r"^\s*([+-]?)[0]+([0-9]+(.[0-9]+)?)\s*$", r"\1\2", value) + return value + + def _RemoveLeadingZerosForNumbersInValues(self, values, width=0): + return [self._RemoveLeadingZerosForNumber(value, width) for value in values] + + def _ParseTransactionCallResponses(self, responses, remove_zeros_width=None): + single_output = None + columns = [] + records = [] + for response in responses: + if single_output is None: + single_output = dict( + zip( + response.single_data.names, + self._RemoveLeadingZerosForNumbersInValues( + response.single_data.values, remove_zeros_width + ), + ) + ) + if not columns: + columns = response.multi_data.names + for values in response.multi_data.values: + records.append( + self._RemoveLeadingZerosForNumbersInValues( + values.values, remove_zeros_width + ) + ) + single = pd.Series(single_output, dtype=object) + multi = pd.DataFrame.from_records(records, columns=columns) + return single, multi + +
[docs] def GetStockBasicInfoAsDict(self, code, rqname=None, scrno=None): + """ + 주식 종목의 기본정보를 딕셔너리 형태로 반환합니다. + + TR: OPT10001 + """ + if rqname is None: + rqname = "주식기본정보요청" + trcode = "opt10001" + inputs = {"종목코드": code} + for response in self.TransactionCall(rqname, trcode, scrno, inputs): + names = response.single_data.names + values = response.single_data.values + result = dict(zip(names, values)) + return result
+ +
[docs] def GetStockBasicInfoAsSeries(self, code, rqname=None, scrno=None): + """ + 주식 종목의 기본정보를 pd.Series 형태로 반환합니다. + + TR: OPT10001 + """ + dic = self.GetStockBasicInfoAsDict(code, rqname, scrno) + series = pd.Series(dic) + return series
+ +
[docs] def GetStockQuoteInfoAsDataFrame(self, codes=None, rqname=None, scrno=None): + """ + 복수개의 주식 종목들의 기본정보를 pd.DataFrame 형태로 반환합니다. + + TR: OPTKWFID + """ + if codes is None: + codes = self.GetGeneralCodeList() + elif isinstance(codes, str): + codes = [codes] + if rqname is None: + rqname = "관심종목정보요청" + trcode = "OPTKWFID" + columns = [] + records = [] + inputs = {"종목코드": ";".join(codes)} + for response in self.TransactionCall(rqname, trcode, scrno, inputs): + if not columns: + columns = response.multi_data.names + for values in response.multi_data.values: + records.append(values.values) + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetTickStockDataAsDataFrame( + self, + code, + interval, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 틱 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10079 + """ + if interval is not None: + interval = int(interval) + interval = str(interval) + + date_format = "%Y%m%d%H%M%S" + date_column_name = "체결시간" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식틱차트조회요청" + trcode = "opt10079" + inputs = { + "종목코드": code, + "틱범위": interval, + "수정주가구분": "1" if adjusted_price else "0", + } + + columns = [] + records = [] + + date_column_index = None + should_compare_start = start_date is not None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + if should_compare_start and date_column_index is not None: + date = values.values[date_column_index] + if date > start_date: + # 해당 TR 은 기준일자를 INPUT 으로 설정할 수 없는 이유로 + # 일단 가장 최근부터 차례대로 가져오고 클라이언트에서 요청보다 최근 데이터는 버림 + # 클라이언트 말고 서버에서 미리 처리해서 데이터를 보내지조차 않아야 할지?? + continue + else: + should_compare_start = False + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetMinuteStockDataAsDataFrame( + self, + code, + interval, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 분 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10080 + """ + if interval is not None: + interval = int(interval) + interval = str(interval) + + date_format = "%Y%m%d%H%M%S" + date_column_name = "체결시간" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식분봉차트조회요청" + trcode = "opt10080" + inputs = { + "종목코드": code, + "틱범위": interval, + "수정주가구분": "1" if adjusted_price else "0", + } + + columns = [] + records = [] + + date_column_index = None + should_compare_start = start_date is not None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + if should_compare_start and date_column_index is not None: + date = values.values[date_column_index] + if date > start_date: + # 해당 TR 은 기준일자를 INPUT 으로 설정할 수 없는 이유로 + # 일단 가장 최근부터 차례대로 가져오고 클라이언트에서 요청보다 최근 데이터는 버림 + # 클라이언트 말고 서버에서 미리 처리해서 데이터를 보내지조차 않아야 할지?? + continue + else: + should_compare_start = False + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetDailyStockDataAsDataFrame( + self, + code, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 일 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10081 + """ + date_format = "%Y%m%d" + date_column_name = "일자" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식일봉차트조회요청" + + trcode = "opt10081" + inputs = { + "종목코드": code, + "수정주가구분": "1" if adjusted_price else "0", + } + if start_date is not None: + inputs["기준일자"] = start_date + + columns = [] + records = [] + + date_column_index = None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetWeeklyStockDataAsDataFrame( + self, + code, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 주 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10082 + """ + date_format = "%Y%m%d" + date_column_name = "일자" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식주봉차트조회요청" + + trcode = "opt10082" + inputs = { + "종목코드": code, + "수정주가구분": "1" if adjusted_price else "0", + } + if start_date is not None: + inputs["기준일자"] = start_date + if end_date is not None: + inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... + + columns = [] + records = [] + date_column_index = None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetMonthlyStockDataAsDataFrame( + self, + code, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 월 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10083 + """ + date_format = "%Y%m%d" + date_column_name = "일자" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식월봉차트조회요청" + + trcode = "opt10083" + inputs = { + "종목코드": code, + "수정주가구분": "1" if adjusted_price else "0", + } + if start_date is not None: + inputs["기준일자"] = start_date + if end_date is not None: + inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... + + columns = [] + records = [] + date_column_index = None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetYearlyStockDataAsDataFrame( + self, + code, + start_date=None, + end_date=None, + include_end=False, + adjusted_price=False, + rqname=None, + scrno=None, + ): + """ + 년 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10094 + """ + date_format = "%Y%m%d" + date_column_name = "일자" + + if isinstance(start_date, datetime.datetime): + start_date = start_date.strftime(date_format) + + if end_date is not None: + if isinstance(end_date, datetime.datetime): + end_date = end_date.strftime(date_format) + stop_condition = { + "name": date_column_name, + "value": end_date, + } + if include_end: + stop_condition["comparator"] = "<" + else: + stop_condition = None + + if rqname is None: + rqname = "주식년봉차트조회요청" + + trcode = "opt10094" + inputs = { + "종목코드": code, + "수정주가구분": "1" if adjusted_price else "0", + } + if start_date is not None: + inputs["기준일자"] = start_date + if end_date is not None: + inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... + + columns = [] + records = [] + date_column_index = None + + for response in self.TransactionCall( + rqname, trcode, scrno, inputs, stop_condition=stop_condition + ): + if not columns: + columns = list(response.multi_data.names) + if date_column_name in columns: + date_column_index = columns.index(date_column_name) + for values in response.multi_data.values: + records.append(values.values) + + if self.logger.isEnabledFor(logging.DEBUG): + nrows = len(response.multi_data.values) + if nrows > 0: + from_date = response.multi_data.values[0].values[date_column_index] + to_date = response.multi_data.values[-1].values[date_column_index] + from_date = datetime.datetime.strptime(from_date, date_format) + to_date = datetime.datetime.strptime(to_date, date_format) + self.logger.debug( + "Received %d records from %s to %s for code %s", + nrows, + from_date, + to_date, + code, + ) + + df = pd.DataFrame.from_records(records, columns=columns) + return df
+ +
[docs] def GetDepositInfo( + self, account_no, lookup_type=None, with_multi=False, rqname=None, scrno=None + ): + """ + 계좌의 예수금 정보를 반환합니다. + + TR: OPW00001 + + 조회구분 = 3:추정조회, 2:일반조회 + """ + if rqname is None: + rqname = "예수금상세현황요청" + trcode = "opw00001" + inputs = { + "계좌번호": account_no, + "비밀번호": "", + "비밀번호입력매체구분": "00", + "조회구분": "2" if lookup_type is None else lookup_type, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, multi = self._ParseTransactionCallResponses(responses, [12, 15]) + if with_multi: + return single, multi + else: + return single
+ +
[docs] def GetStockQuotes(self, code, rqname=None, scrno=None): + """ + 주식의 호가정보를 반환합니다. + + TR: OPT10004 + """ + if rqname is None: + rqname = "주식호가요청" + trcode = "opt10004" + inputs = { + "종목코드": code, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, _multi = self._ParseTransactionCallResponses(responses, [12, 15]) + return single
+ +
[docs] def GetOrderLogAsDataFrame1( + self, + account_no, + order_type=None, + status_type=None, + code=None, + rqname=None, + scrno=None, + ): + """ + 미체결 주문 정보를 반환합니다. + + TR: OPT10075 + + 계좌번호 = 전문 조회할 보유계좌번호 + 전체종목구분 = 0:전체, 1:종목 + 매매구분 = 0:전체, 1:매도, 2:매수 + 종목코드 = 전문 조회할 종목코드 + 체결구분 = 0:전체, 2:체결, 1:미체결 + """ + + if rqname is None: + rqname = "실시간미체결요청" + trcode = "opt10075" + inputs = { + "계좌번호": account_no, + "전체종목구분": "0" if code is None else "1", + "매매구분": "0" if order_type is None else order_type, + "종목코드": "" if code is None else code, + "체결구분": "0" if status_type is None else status_type, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + _single, multi = self._ParseTransactionCallResponses(responses) + return multi
+ +
[docs] def GetOrderLogAsDataFrame2( + self, + account_no, + order_type=None, + status_type=None, + code=None, + order_no=None, + rqname=None, + scrno=None, + ): + """ + 주문 체결 정보를 반환합니다. + + TR: OPT10076 + + 종목코드 = 전문 조회할 종목코드 + 조회구분 = 0:전체, 1:종목 + 매도수구분 = 0:전체, 1:매도, 2:매수 + 계좌번호 = 전문 조회할 보유계좌번호 + 비밀번호 = 사용안함(공백) + 주문번호 = 조회할 주문번호 + 체결구분 = 0:전체, 2:체결, 1:미체결 + """ + + if rqname is None: + rqname = "실시간체결요청" + trcode = "opt10076" + inputs = { + "종목코드": "" if code is None else code, + "조회구분": "0" if code is None else "1", + "매도수구분": "0" if order_type is None else order_type, + "계좌번호": account_no, + "비밀번호": "", + "주문번호": "" if order_no is None else order_no, + "체결구분": "0" if status_type is None else status_type, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + _single, multi = self._ParseTransactionCallResponses(responses) + return multi
+ +
[docs] def GetOrderLogAsDataFrame3( + self, + account_no, + date=None, + sort_type=None, + asset_type=None, + order_type=None, + code=None, + starting_order_no=None, + rqname=None, + scrno=None, + ): + """ + 계좌별 주문 체결 내역을 반환합니다. + + TR: OPW00007 + + 주문일자 = YYYYMMDD (20170101 연도4자리, 월 2자리, 일 2자리 형식) + 계좌번호 = 전문 조회할 보유계좌번호 + 비밀번호 = 사용안함(공백) + 비밀번호입력매체구분 = 00 + 조회구분 = 1:주문순, 2:역순, 3:미체결, 4:체결내역만 + 주식채권구분 = 0:전체, 1:주식, 2:채권 + 매도수구분 = 0:전체, 1:매도, 2:매수 + 종목코드 + 시작주문번호 + """ + + if rqname is None: + rqname = "계좌별주문체결내역상세요청" + trcode = "opw00007" + if date is None: + now = datetime.datetime.now() + market_start_time = now.replace(hour=8, minute=20, second=0, microsecond=0) + if now < market_start_time: + now = now - datetime.timedelta(days=1) + date = now.strftime("%Y%m%d") + inputs = { + "주문일자": date, + "계좌번호": account_no, + "비밀번호": "", + "비밀번호입력매체구분": "00", + "조회구분": "1" if sort_type is None else sort_type, + "주식채권구분": "0" if asset_type is None else asset_type, + "매도수구분": "0" if order_type is None else order_type, + "종목코드": "" if code is None else code, + "시작주문번호": "" if starting_order_no is None else starting_order_no, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + _single, multi = self._ParseTransactionCallResponses(responses, 10) + return multi
+ +
[docs] def GetAccountRateOfReturnAsDataFrame(self, account_no, rqname=None, scrno=None): + """ + 계좌별 수익률 정보를 반환합니다. + + TR: OPT10085 + """ + if rqname is None: + rqname = "계좌수익률요청" + trcode = "opt10085" + inputs = { + "계좌번호": account_no, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + _single, multi = self._ParseTransactionCallResponses(responses, 10) + return multi
+ +
[docs] def GetAccountEvaluationStatusAsSeriesAndDataFrame( + self, account_no, include_delisted=True, rqname=None, scrno=None + ): + """ + 계좌의 평가 현황 정보를 반환합니다. + + TR: OPW00004 + """ + if rqname is None: + rqname = "계좌평가현황요청" + trcode = "opw00004" + inputs = { + "계좌번호": account_no, + "비밀번호": "", + "상장폐지조회구분": "0" if include_delisted else "1", + "비밀번호입력매체구분": "00", + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, multi = self._ParseTransactionCallResponses(responses, 12) + return single, multi
+ +
[docs] def GetAccountExecutionBalanceAsSeriesAndDataFrame( + self, account_no, rqname=None, scrno=None + ): + """ + 계좌의 체결 잔고 정보를 반환합니다. + + TR: OPW00005 + + 모의투자에서는 지원하지 않는 TR 입니다. + """ + server = self.GetServerGubun() + if server == "1": + self.logger.warning("Not supported for simulated investment") + if rqname is None: + rqname = "체결잔고요청" + if scrno is None: + scrno = "1010" + trcode = "opw00005" # 모의투자에서 지원하지 않는 TR + inputs = { + "계좌번호": account_no, + "비밀번호": "", + "비밀번호입력매체구분": "00", + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, multi = self._ParseTransactionCallResponses(responses, 0) + return single, multi
+ +
[docs] def GetAccountEvaluationBalanceAsSeriesAndDataFrame( + self, account_no, lookup_type=None, rqname=None, scrno=None + ): + """ + 계좌의 평가 잔고 내역 정보를 반환합니다. + + TR: OPW00018 + + 조회구분 = 1:합산, 2:개별 + + [ 주의 ] + "수익률%" 데이터는 모의투자에서는 소숫점표현, 실거래서버에서는 소숫점으로 변환 필요 합니다. + """ + if rqname is None: + rqname = "계좌평가잔고내역요청" + trcode = "opw00018" + inputs = { + "계좌번호": account_no, + "비밀번호": "", + "비밀번호입력매체구분": "00", + "조회구분": "2" if lookup_type is None else str(lookup_type), + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, multi = self._ParseTransactionCallResponses(responses, [12, 15]) + return single, multi
+ +
[docs] def GetMarketPriceInfo(self, code, rqname=None, scrno=None): + """ + 종목의 시세표성 정보를 반환합니다. + + TR: OPT10007 + """ + if rqname is None: + rqname = "시세표성정보요청" + trcode = "opt10007" + inputs = { + "종목코드": code, + } + responses = self.TransactionCall(rqname, trcode, scrno, inputs) + single, _multi = self._ParseTransactionCallResponses(responses) + return single
+ +
[docs] def GetRealDataForCodesAsStream( + self, + codes, + fids=None, + opt_type=None, + screen_no=None, + infer_fids=False, + readable_names=False, + fast_parse=False, + ): + """ + 실시간 데이터를 요청하고 스트림 형태로 반환받습니다. + """ + if isinstance(codes, str): + codes = [codes] + if fids is None: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( + KiwoomOpenApiPlusRealType, + ) + + fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") + if opt_type is None: + opt_type = "0" + assert opt_type in ["0", "1"], "opt_type should be either 0 or 1" + responses = self.RealCall( + screen_no, codes, fids, opt_type, infer_fids, readable_names, fast_parse + ) + return responses
+ +
[docs] def GetCodeListByCondition( + self, + condition_name, + condition_index=None, + with_info=False, + is_future_option=False, + request_name=None, + screen_no=None, + ): + """ + 주어진 조건식으로 조건검색을 수행하고 + 검색된 종목의 종목코드를 리스트로 반환받습니다. + + 파라미터 중 with_info 가 True 로 설정된 경우, + 검색된 종목들에 대한 기본 정보도 추가로 같이 반환됩니다. + """ + search_type = 0 + + if condition_index is None: + condition_names = self.GetConditionNameListAsList() + condition_indices = {item[1]: item[0] for item in condition_names} + condition_index = condition_indices[condition_name] + + codes = [] + + single_output = None + columns = [] + records = [] + remove_zeros_width = None + + for response in self.ConditionCall( + screen_no, + condition_name, + condition_index, + search_type, + with_info, + is_future_option, + request_name, + ): + if response.name == "OnReceiveTrCondition": + code_list = response.arguments[1].string_value + code_list = code_list.rstrip(";").split(";") if code_list else [] + codes.extend(code_list) + elif response.name == "OnReceiveTrData": + if single_output is None: + single_output = dict( + zip( + response.single_data.names, + self._RemoveLeadingZerosForNumbersInValues( + response.single_data.values, remove_zeros_width + ), + ) + ) + if not columns: + columns = response.multi_data.names + for values in response.multi_data.values: + records.append( + self._RemoveLeadingZerosForNumbersInValues( + values.values, remove_zeros_width + ) + ) + else: + raise ValueError("Unexpected event handler name %s" % response.name) + + _single = pd.Series(single_output, dtype=object) + multi = pd.DataFrame.from_records(records, columns=columns) + + if with_info: + return codes, multi + else: + return codes
+ + def _GetCodeListByConditionAsStream_GeneratorFunc(self, responses, with_info=False): + for response in responses: + if response.name == "OnReceiveTrCondition": + code_list = response.arguments[1].string_value + code_list = code_list.rstrip(";").split(";") if code_list else [] + inserted = code_list + deleted = [] + if with_info: + info = None + yield inserted, deleted, info + else: + yield inserted, deleted + elif response.name == "OnReceiveRealCondition": + code = response.arguments[0].string_value + condition_type = response.arguments[1].string_value + inserted = [] + deleted = [] + if condition_type == "I": + inserted.append(code) + elif condition_type == "D": + deleted.append(code) + else: + raise ValueError("Unexpected condition type %s" % condition_type) + if with_info: + info = None + yield inserted, deleted, info + else: + yield inserted, deleted + elif response.name == "OnReceiveTrData": + single_output = None + columns = [] + records = [] + remove_zeros_width = None + if single_output is None: + single_output = dict( + zip( + response.single_data.names, + self._RemoveLeadingZerosForNumbersInValues( + response.single_data.values, remove_zeros_width + ), + ) + ) + if not columns: + columns = response.multi_data.names + for values in response.multi_data.values: + records.append( + self._RemoveLeadingZerosForNumbersInValues( + values.values, remove_zeros_width + ) + ) + _single = pd.Series(single_output, dtype=object) + multi = pd.DataFrame.from_records(records, columns=columns) + inserted = [] + deleted = [] + if with_info: + info = multi + yield inserted, deleted, info + else: + raise RuntimeError( + "Unexpected, OnReceiveTrData event with with_info=False ???" + ) + else: + raise ValueError("Unexpected event handler name %s" % response.name) + +
[docs] def GetCodeListByConditionAsStream( + self, + condition_name, + condition_index=None, + with_info=False, + is_future_option=False, + request_name=None, + screen_no=None, + old_behavior=False, + ): + """ + 주어진 조건식을 실시간 조건검색으로 등록합니다. + 이후 발생하는 이벤트들을 스트림 형태로 제공합니다. + + 최초 검색결과는 OnReceiveTrCondition() 이벤트로 반환되며 + 이후 종목의 추가/제외는 OnReceiveRealCondition() 이벤트로 반환됩니다. + + 만약 with_info 가 True 로 설정된 경우, + 검색된 종목마다 추가적인 정보가 OnReceiveTrData() 이벤트를 통해 반환됩니다. + """ + search_type = 1 + + if condition_index is None: + condition_names = self.GetConditionNameListAsList() + condition_indices = {item[1]: item[0] for item in condition_names} + condition_index = condition_indices[condition_name] + + responses = self.ConditionCall( + screen_no, + condition_name, + condition_index, + search_type, + with_info, + is_future_option, + request_name, + ) + + if not old_behavior: + return responses + + stream = PipeableMultiThreadedRendezvous(responses) + stream = stream.pipe( + lambda responses: self._GetCodeListByConditionAsStream_GeneratorFunc( + responses, with_info=with_info + ) + ) + + return stream
+ + +
[docs]class KiwoomOpenApiPlusServiceClientStubWrapper( + KiwoomOpenApiPlusServiceClientStubExtendedWrapper +): + """ + KiwoomOpenApiPlusServiceClientStubCoreWrapper, KiwoomOpenApiPlusServiceClientStubExtendedWrapper 의 구현 및 + KiwoomOpenApiPlusQAxWidgetUniversalMixin 의 구현들까지 최종적으로 포함된 + KiwoomOpenApiPlusServiceClientStub 객체를 위한 Mixin 래퍼 클래스 입니다. + """
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.html new file mode 100644 index 00000000..dd6550b8 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.html @@ -0,0 +1,167 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils

+
[docs]def convert_arguments_from_protobuf_to_python(arguments): + args = [] + for argument in arguments: + if argument.HasField("string_value"): + args.append(argument.string_value) + elif argument.HasField("bool_value"): + args.append(argument.bool_value) + elif argument.HasField("long_value"): + args.append(argument.long_value) + else: + raise ValueError("No expecting field found.") + return args
+ + +
[docs]def convert_arguments_from_python_to_protobuf(arguments, arguments_message): + for i, arg in enumerate(arguments): + if isinstance(arg, str): + arguments_message.add().string_value = arg + elif isinstance(arg, bool): + arguments_message.add().bool_value = arg + elif isinstance(arg, int): + arguments_message.add().long_value = arg + else: + raise TypeError("Unexpected type for argument %d: %s" % (i, type(arg))) + return arguments_message
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.html new file mode 100644 index 00000000..f4a01a69 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.html @@ -0,0 +1,293 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer

+import inspect
+
+from concurrent.futures import ThreadPoolExecutor
+
+import grpc
+
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2_grpc
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer import (
+    KiwoomOpenApiPlusServiceServicer,
+)
+from koapy.config import config
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.networking import find_free_port_for_host, is_in_private_network
+
+
+
[docs]class KiwoomOpenApiPlusServiceServer(Logging): + def __init__( + self, + control, + host=None, + port=None, + credentials=None, + **kwargs, + ): + if host is None: + host = config.get_string( + "koapy.backend.kiwoom_open_api_plus.grpc.host", "localhost" + ) + host = config.get_string( + "koapy.backend.kiwoom_open_api_plus.grpc.server.host", host + ) + if port is None: + port = config.get_int("koapy.backend.kiwoom_open_api_plus.grpc.port", 0) + port = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.server.port", port + ) + + if port == 0: + port = find_free_port_for_host(host) + self.logger.info( + "Using one of the free ports, final address would be %s:%d", host, port + ) + + self._control = control + self._host = host + self._port = port + self._credentials = credentials + self._kwargs = dict(kwargs) + + self._servicer = KiwoomOpenApiPlusServiceServicer(self._control) + self._address = self._host + ":" + str(self._port) + + grpc_server_signature = inspect.signature(grpc.server) + grpc_server_params = list(grpc_server_signature.parameters.keys()) + grpc_server_kwargs = { + k: v for k, v in self._kwargs.items() if k in grpc_server_params + } + grpc_server_bound_arguments = grpc_server_signature.bind_partial( + **grpc_server_kwargs + ) + if grpc_server_bound_arguments.arguments.get("thread_pool") is None: + thread_pool_signature = inspect.signature(ThreadPoolExecutor) + thread_pool_params = list(thread_pool_signature.parameters.keys()) + thread_pool_kwargs = { + k: v for k, v in self._kwargs.items() if k in thread_pool_params + } + thread_pool_bound_arguments = thread_pool_signature.bind( + **thread_pool_kwargs + ) + if thread_pool_bound_arguments.arguments.get("max_workers") is None: + max_workers = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.server.max_workers", 8 + ) + thread_pool_bound_arguments.arguments["max_workers"] = max_workers + thread_pool = ThreadPoolExecutor( + *thread_pool_bound_arguments.args, + **thread_pool_bound_arguments.kwargs, + ) + grpc_server_bound_arguments.arguments["thread_pool"] = thread_pool + self._thread_pool = thread_pool + else: + self._thread_pool = grpc_server_bound_arguments.arguments["thread_pool"] + + self._grpc_server_bound_arguments = grpc_server_bound_arguments + + self._server = None + self._server_started = False + self._server_stopped = False + + self.reinitialize_server() + +
[docs] def reinitialize_server(self): + if self._server is not None: + self.stop() + self.wait_for_termination() + + self._server = grpc.server( + *self._grpc_server_bound_arguments.args, + **self._grpc_server_bound_arguments.kwargs, + ) + self._server_started = False + self._server_stopped = False + + KiwoomOpenApiPlusService_pb2_grpc.add_KiwoomOpenApiPlusServiceServicer_to_server( + self._servicer, self._server + ) + + if self._credentials is None: + if not is_in_private_network(self._host): + self.logger.warning( + "Adding insecure port %s to server, but the address is not private.", + self._address, + ) + self._server.add_insecure_port(self._address) + else: + self._server.add_secure_port(self._address, self._credentials)
+ +
[docs] def get_host(self): + return self._host
+ +
[docs] def get_port(self): + return self._port
+ +
[docs] def start(self): + if self._server_started and self._server_stopped: + self.reinitialize_server() + if not self._server_started: + self._server.start() + self._server_started = True
+ +
[docs] def wait_for_termination(self, timeout=None): + return self._server.wait_for_termination(timeout)
+ +
[docs] def is_running(self): + return self.wait_for_termination(1)
+ +
[docs] def stop(self, grace=None): + event = self._server.stop(grace) + self._server_stopped = True + return event
+ + def __getattr__(self, name): + return getattr(self._server, name) + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.stop() + self.wait_for_termination()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.html new file mode 100644 index 00000000..fd60f211 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.html @@ -0,0 +1,514 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer

+import logging
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import (
+    KiwoomOpenApiPlusEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager import (
+    KiwoomOpenApiPlusScreenManager,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import (
+    KiwoomOpenApiPlusService_pb2,
+    KiwoomOpenApiPlusService_pb2_grpc,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler import (
+    KiwoomOpenApiPlusConditionEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers import (
+    KiwoomOpenApiPlusAllEventHandler,
+    KiwoomOpenApiPlusSomeBidirectionalEventHandler,
+    KiwoomOpenApiPlusSomeEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler import (
+    KiwoomOpenApiPlusKwTrEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler import (
+    KiwoomOpenApiPlusLoadConditionEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler import (
+    KiwoomOpenApiPlusLoginEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler import (
+    KiwoomOpenApiPlusAllOrderEventHandler,
+    KiwoomOpenApiPlusOrderEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler import (
+    KiwoomOpenApiPlusBidirectionalRealEventHandler,
+    KiwoomOpenApiPlusRealEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler import (
+    KiwoomOpenApiPlusTrEventHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import (
+    convert_arguments_from_protobuf_to_python,
+)
+
+
+
[docs]class KiwoomOpenApiPlusServiceServicer( + KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer +): + """ + KiwoomOpenApiPlusService RPC 의 구현체 입니다. + """ + + def __init__(self, control): + super().__init__() + + self._control = control + self._screen_manager = KiwoomOpenApiPlusScreenManager(self._control) + + @property +
[docs] def control(self): + return self._control
+ + @property +
[docs] def screen_manager(self): + return self._screen_manager
+ + # 1. rpcs for general function calls + +
[docs] def Call(self, request, context): + """ + 임의의 함수 호출을 위한 RPC 입니다. + + 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 + 호출결과를 응답 메시지를 통해 전달합니다. + + 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. + """ + name = request.name + arguments = convert_arguments_from_protobuf_to_python(request.arguments) + function = getattr(self.control, name) + result = function(*arguments) + response = KiwoomOpenApiPlusService_pb2.CallResponse() + if isinstance(result, str): + response.return_value.string_value = result + elif isinstance(result, bool): + response.return_value.bool_value = result + elif isinstance(result, int): + response.return_value.long_value = result + elif result is None: + pass + else: + raise TypeError( + "Unexpected return value type from server side dynamicCall(): %s" + % type(result) + ) + return response
+ + # 2. rpcs for listening and handling events + +
[docs] def Listen(self, request, context): + """ + 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. + + 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. + 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. + + 서버측의 이벤트 핸들러 함수는 해당 이벤트를 클라이언트에 전송한 이후 즉시 종료됩니다. + """ + with KiwoomOpenApiPlusSomeEventHandler( + self.control, request, context + ) as handler: + for response in handler: + yield response
+ +
[docs] def BidirectionalListen(self, request_iterator, context): + """ + 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. + + 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. + 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. + + 앞선 Listen() RPC 와 다르게 해당 RPC 는 이벤트 발생시 서버측에서는 이벤트 내용을 응답 메시지로 전달한 다음 + 다시 클라이언트 측에서 ACK 요청을 줄 때 까지 서버측 이벤트 핸들러 함수 내에서 대기합니다. + 따라서 클라이언트는 서버측 이벤트 핸들러 함수 컨텍스트 내에서 이벤트를 처리할 수 있고 + 처리를 완료하면 다시 서버측으로 ACK 요청을 보내 서버측 이벤트 핸들러가 완료될 수 있도록 해야 합니다. + """ + with KiwoomOpenApiPlusSomeBidirectionalEventHandler( + self.control, request_iterator, context + ) as handler: + for response in handler: + yield response
+ + # 3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns + +
[docs] def LoginCall(self, request, context): + """ + 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. + + CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + with KiwoomOpenApiPlusLoginEventHandler( + self.control, request, context + ) as handler: + for response in handler: + yield response
+ +
[docs] def TransactionCall(self, request, context): + """ + TR 요청에 해당하는 RPC 입니다. + + CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. + + 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 + 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. + + 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 + 내부적으로 호출됩니다. + + 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 + 대기시간이 발생할 수 있습니다. + + 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. + 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, + TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. + """ + trcode = request.transaction_code.upper() + + if trcode in ["OPTKWFID", "OPTFOFID"]: + handler = KiwoomOpenApiPlusKwTrEventHandler( + self.control, request, context, self.screen_manager + ) + else: + handler = KiwoomOpenApiPlusTrEventHandler( + self.control, request, context, self.screen_manager + ) + + with handler: + for response in handler: + yield response
+ +
[docs] def OrderCall(self, request, context): + """ + 주문 요청에 해당하는 RPC 입니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 + 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. + + 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. + 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. + + 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. + + 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. + """ + with KiwoomOpenApiPlusOrderEventHandler( + self.control, request, context, self.screen_manager + ) as handler: + for response in handler: + yield response
+ +
[docs] def RealCall(self, request, context): + """ + 실시간 데이터 요청에 해당하는 RPC 입니다. + + SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 + 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. + + 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 + 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. + 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. + """ + with KiwoomOpenApiPlusRealEventHandler( + self.control, request, context, self.screen_manager + ) as handler: + for response in handler: + yield response
+ +
[docs] def LoadConditionCall(self, request, context): + """ + 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. + + GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + with KiwoomOpenApiPlusLoadConditionEventHandler( + self.control, request, context + ) as handler: + for response in handler: + yield response
+ +
[docs] def ConditionCall(self, request, context): + """ + 조건검색 기능에 해당하는 RPC 입니다. + + SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 + 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. + """ + with KiwoomOpenApiPlusConditionEventHandler( + self.control, request, context, self.screen_manager + ) as handler: + for response in handler: + yield response
+ + # 4. rpcs for more complex use cases based on the previously categorized simple cases above + +
[docs] def BidirectionalRealCall(self, request_iterator, context): + """ + 실시간 데이터 요청에 해당하는 RPC 입니다. + + 기존의 RealCall() RPC 는 최초 실시간 데이터 등록 이후 이벤트를 듣는 것만 가능했다면 + 새로운 BidirectionalRealCall() 에서는 최초 설정된 이벤트 스트림을 계속 유지하면서 + 신규 실시간 데이터 등록 혹은 해지를 추가로 요청해 반영할 수 있습니다. + """ + with KiwoomOpenApiPlusBidirectionalRealEventHandler( + self.control, request_iterator, context, self.screen_manager + ) as handler: + for response in handler: + yield response
+ +
[docs] def OrderListen(self, request, context): + """ + 주문 이벤트를 듣고 싶을때 사용할 수 있는 RPC 입니다. + + 기존의 OrderCall() RPC 는 특정 주문을 수행하고 해당 주문과 관련된 이벤트들만 반환했다면 + 해당 RPC 는 특정 주문 수행 없이 모든 주문관련 이벤트를 듣고 싶을때 사용할 수 있습니다. + """ + with KiwoomOpenApiPlusAllOrderEventHandler(self.control, context) as handler: + for response in handler: + yield response
+ + # 5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) + +
[docs] def CustomListen(self, request, context): + """ + 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. + + 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, + 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. + + 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. + """ + code = request.code + class_name = request.class_name + if code and class_name: + global_vars = {} + local_vars = {} + exec(code, global_vars, local_vars) # pylint: disable=exec-used + handler = eval(class_name, global_vars, local_vars)( + self.control, request, context + ) # pylint: disable=eval-used + assert isinstance(handler, KiwoomOpenApiPlusEventHandler) + else: + handler = KiwoomOpenApiPlusAllEventHandler(self.control, context) + with handler: + for response in handler: + yield response
+ +
[docs] def CustomCallAndListen(self, request, context): + """ + 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. + + 앞선 CustomListen() 과의 차이점은 요청시 특정 함수를 최초 1회 호출하고 이후 들어오는 이벤트를 처리한다는 점입니다. + + 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, + 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. + + 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. + """ + name = request.name + arguments = convert_arguments_from_protobuf_to_python(request.arguments) + function = getattr(self.control, name) + code = request.listen_request.code + class_name = request.listen_request.class_name + if code and class_name: + global_vars = {} + local_vars = {} + exec(code, global_vars, local_vars) # pylint: disable=exec-used + handler = eval(class_name, global_vars, local_vars)( + self.control, request, context + ) # pylint: disable=eval-used + assert isinstance(handler, KiwoomOpenApiPlusEventHandler) + else: + handler = KiwoomOpenApiPlusAllEventHandler(self.control, context) + with handler: + result = function(*arguments) + response = KiwoomOpenApiPlusService_pb2.CallAndListenResponse() + if isinstance(result, str): + response.call_response.return_value.string_value = ( + result # pylint: disable=no-member + ) + elif isinstance(result, int): + response.call_response.return_value.long_value = ( + result # pylint: disable=no-member + ) + elif result is None: + pass + else: + raise TypeError( + "Unexpected return value type from server side dynamicCall(): %s" + % type(result) + ) + yield response + for listen_response in handler: + response = KiwoomOpenApiPlusService_pb2.CallAndListenResponse() + response.listen_response = listen_response + yield response
+ + # 6. rpcs for other mics scenarios + +
[docs] def SetLogLevel(self, request, context): + """ + 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. + """ + level = request.level + logger = request.logger + logging.getLogger(logger).setLevel(level) + response = KiwoomOpenApiPlusService_pb2.SetLogLevelResponse() + return response
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.html new file mode 100644 index 00000000..0c2fdf6c --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.html @@ -0,0 +1,2247 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2

+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+
[docs]DESCRIPTOR = _descriptor.FileDescriptor( + name='koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto', + package='koapy.backend.kiwoom_open_api_plus.grpc', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\nFkoapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto\x12\'koapy.backend.kiwoom_open_api_plus.grpc\"W\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x14\n\nlong_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"a\n\x0b\x43\x61llRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\targuments\x18\x02 \x03(\x0b\x32\x31.koapy.backend.kiwoom_open_api_plus.grpc.Argument\"Z\n\x0bReturnValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x14\n\nlong_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"Z\n\x0c\x43\x61llResponse\x12J\n\x0creturn_value\x18\x01 \x01(\x0b\x32\x34.koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue\"L\n\rListenRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05slots\x18\x02 \x03(\t\x12\x0c\n\x04\x63ode\x18\x03 \x01(\t\x12\x12\n\nclass_name\x18\x04 \x01(\t\"\x1e\n\x0eHandledRequest\x12\x0c\n\x04time\x18\x01 \x01(\x02\"!\n\x11StopListenRequest\x12\x0c\n\x04time\x18\x01 \x01(\x02\"\xa8\x02\n\x1a\x42idirectionalListenRequest\x12P\n\x0elisten_request\x18\x01 \x01(\x0b\x32\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequestH\x00\x12R\n\x0fhandled_request\x18\x02 \x01(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.HandledRequestH\x00\x12Y\n\x13stop_listen_request\x18\x03 \x01(\x0b\x32:.koapy.backend.kiwoom_open_api_plus.grpc.StopListenRequestH\x00\x42\t\n\x07request\"+\n\nSingleData\x12\r\n\x05names\x18\x01 \x03(\t\x12\x0e\n\x06values\x18\x02 \x03(\t\" \n\x0eRepeatedString\x12\x0e\n\x06values\x18\x01 \x03(\t\"c\n\tMultiData\x12\r\n\x05names\x18\x01 \x03(\t\x12G\n\x06values\x18\x02 \x03(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.RepeatedString\"\xf6\x01\n\x0eListenResponse\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\targuments\x18\x02 \x03(\x0b\x32\x31.koapy.backend.kiwoom_open_api_plus.grpc.Argument\x12H\n\x0bsingle_data\x18\x03 \x01(\x0b\x32\x33.koapy.backend.kiwoom_open_api_plus.grpc.SingleData\x12\x46\n\nmulti_data\x18\x04 \x01(\x0b\x32\x32.koapy.backend.kiwoom_open_api_plus.grpc.MultiData\"\xb2\x01\n\x14\x43\x61llAndListenRequest\x12J\n\x0c\x63\x61ll_request\x18\x01 \x01(\x0b\x32\x34.koapy.backend.kiwoom_open_api_plus.grpc.CallRequest\x12N\n\x0elisten_request\x18\x02 \x01(\x0b\x32\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\"\xc7\x01\n\x15\x43\x61llAndListenResponse\x12N\n\rcall_response\x18\x01 \x01(\x0b\x32\x35.koapy.backend.kiwoom_open_api_plus.grpc.CallResponseH\x00\x12R\n\x0flisten_response\x18\x02 \x01(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponseH\x00\x42\n\n\x08response\"\x8d\x02\n\x10LoginCredentials\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x15\n\ruser_password\x18\x02 \x01(\t\x12\x15\n\rcert_password\x18\x03 \x01(\t\x12\x15\n\ris_simulation\x18\x04 \x01(\x08\x12j\n\x11\x61\x63\x63ount_passwords\x18\x05 \x03(\x0b\x32O.koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry\x1a\x37\n\x15\x41\x63\x63ountPasswordsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"^\n\x0cLoginRequest\x12N\n\x0b\x63redentials\x18\x01 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials\"R\n\x10RealRequestFlags\x12\x12\n\ninfer_fids\x18\x01 \x01(\x08\x12\x16\n\x0ereadable_names\x18\x02 \x01(\x08\x12\x12\n\nfast_parse\x18\x03 \x01(\x08\"\xa1\x01\n\x0bRealRequest\x12\x11\n\tscreen_no\x18\x01 \x03(\t\x12\x11\n\tcode_list\x18\x02 \x03(\t\x12\x10\n\x08\x66id_list\x18\x03 \x03(\x05\x12\x10\n\x08opt_type\x18\x04 \x01(\t\x12H\n\x05\x66lags\x18\x05 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\"\x97\x01\n\x18TransactionStopCondition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12^\n\ncomparator\x18\x03 \x01(\x0e\x32J.koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopConditionCompartor\"\x84\x03\n\x12TransactionRequest\x12\x14\n\x0crequest_name\x18\x01 \x01(\t\x12\x18\n\x10transaction_code\x18\x02 \x01(\t\x12\x11\n\tscreen_no\x18\x03 \x01(\t\x12W\n\x06inputs\x18\x04 \x03(\x0b\x32G.koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry\x12Y\n\x0estop_condition\x18\x05 \x01(\x0b\x32\x41.koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition\x12H\n\x05\x66lags\x18\x06 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\x1a-\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"]\n\x17OrderSubscriptionTarget\x12\x0b\n\x03RET\x18\x01 \x01(\x08\x12\n\n\x02TR\x18\x02 \x01(\x08\x12\x0c\n\x04REAL\x18\x03 \x01(\x08\x12\x0b\n\x03MSG\x18\x04 \x01(\x08\x12\x0e\n\x06\x43HEJAN\x18\x05 \x01(\x08\"\x8f\x02\n\x0cOrderRequest\x12\x14\n\x0crequest_name\x18\x01 \x01(\t\x12\x11\n\tscreen_no\x18\x02 \x01(\t\x12\x12\n\naccount_no\x18\x03 \x01(\t\x12\x12\n\norder_type\x18\x04 \x01(\x03\x12\x0c\n\x04\x63ode\x18\x05 \x01(\t\x12\x10\n\x08quantity\x18\x06 \x01(\x03\x12\r\n\x05price\x18\x07 \x01(\x03\x12\x12\n\nquote_type\x18\x08 \x01(\t\x12\x19\n\x11original_order_no\x18\t \x01(\t\x12P\n\x06target\x18\n \x01(\x0b\x32@.koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget\"\x16\n\x14LoadConditionRequest\"D\n\x15\x43onditionRequestFlags\x12\x11\n\twith_info\x18\x01 \x01(\x08\x12\x18\n\x10is_future_option\x18\x02 \x01(\x08\"\xd0\x01\n\x10\x43onditionRequest\x12\x11\n\tscreen_no\x18\x01 \x01(\t\x12\x16\n\x0e\x63ondition_name\x18\x02 \x01(\t\x12\x17\n\x0f\x63ondition_index\x18\x03 \x01(\x05\x12\x13\n\x0bsearch_type\x18\x04 \x01(\x05\x12\x14\n\x0crequest_name\x18\x05 \x01(\t\x12M\n\x05\x66lags\x18\x06 \x01(\x0b\x32>.koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags\"3\n\x12SetLogLevelRequest\x12\r\n\x05level\x18\x01 \x01(\x05\x12\x0e\n\x06logger\x18\x02 \x01(\t\"\x15\n\x13SetLogLevelResponse\"\x80\x01\n\"BidirectionalRealInitializeRequest\x12\x10\n\x08\x66id_list\x18\x01 \x03(\x05\x12H\n\x05\x66lags\x18\x02 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\"G\n BidirectionalRealRegisterRequest\x12\x11\n\tcode_list\x18\x01 \x03(\t\x12\x10\n\x08\x66id_list\x18\x02 \x03(\x05\"3\n\x1e\x42idirectionalRealRemoveRequest\x12\x11\n\tcode_list\x18\x01 \x03(\t\"\x1e\n\x1c\x42idirectionalRealStopRequest\"\xb9\x03\n\x18\x42idirectionalRealRequest\x12i\n\x12initialize_request\x18\x01 \x01(\x0b\x32K.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequestH\x00\x12\x65\n\x10register_request\x18\x02 \x01(\x0b\x32I.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequestH\x00\x12\x61\n\x0eremove_request\x18\x03 \x01(\x0b\x32G.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRemoveRequestH\x00\x12]\n\x0cstop_request\x18\x04 \x01(\x0b\x32\x45.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealStopRequestH\x00\x42\t\n\x07request*\x9d\x01\n!TransactionStopConditionCompartor\x12\x19\n\x15LESS_THAN_OR_EQUAL_TO\x10\x00\x12\r\n\tLESS_THAN\x10\x01\x12\x1c\n\x18GREATER_THAN_OR_EQUAL_TO\x10\x02\x12\x10\n\x0cGREATER_THAN\x10\x03\x12\x0c\n\x08\x45QUAL_TO\x10\x04\x12\x10\n\x0cNOT_EQUAL_TO\x10\x05\x32\xa6\x0f\n\x18KiwoomOpenApiPlusService\x12u\n\x04\x43\x61ll\x12\x34.koapy.backend.kiwoom_open_api_plus.grpc.CallRequest\x1a\x35.koapy.backend.kiwoom_open_api_plus.grpc.CallResponse\"\x00\x12}\n\x06Listen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x99\x01\n\x13\x42idirectionalListen\x12\x43.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00(\x01\x30\x01\x12\x7f\n\tLoginCall\x12\x35.koapy.backend.kiwoom_open_api_plus.grpc.LoginRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x8b\x01\n\x0fTransactionCall\x12;.koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x7f\n\tOrderCall\x12\x35.koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12}\n\x08RealCall\x12\x34.koapy.backend.kiwoom_open_api_plus.grpc.RealRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x8f\x01\n\x11LoadConditionCall\x12=.koapy.backend.kiwoom_open_api_plus.grpc.LoadConditionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x87\x01\n\rConditionCall\x12\x39.koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x99\x01\n\x15\x42idirectionalRealCall\x12\x41.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00(\x01\x30\x01\x12\x82\x01\n\x0bOrderListen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x83\x01\n\x0c\x43ustomListen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x98\x01\n\x13\x43ustomCallAndListen\x12=.koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest\x1a>.koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse\"\x00\x30\x01\x12\x8a\x01\n\x0bSetLogLevel\x12;.koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest\x1a<.koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelResponse\"\x00\x62\x06proto3' +)
+ +_TRANSACTIONSTOPCONDITIONCOMPARTOR = _descriptor.EnumDescriptor( + name='TransactionStopConditionCompartor', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopConditionCompartor', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='LESS_THAN_OR_EQUAL_TO', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='LESS_THAN', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='GREATER_THAN_OR_EQUAL_TO', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='GREATER_THAN', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='EQUAL_TO', index=4, number=4, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='NOT_EQUAL_TO', index=5, number=5, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=4388, + serialized_end=4545, +) +_sym_db.RegisterEnumDescriptor(_TRANSACTIONSTOPCONDITIONCOMPARTOR) + +
[docs]TransactionStopConditionCompartor = enum_type_wrapper.EnumTypeWrapper(_TRANSACTIONSTOPCONDITIONCOMPARTOR)
+
[docs]LESS_THAN_OR_EQUAL_TO = 0
+
[docs]LESS_THAN = 1
+
[docs]GREATER_THAN_OR_EQUAL_TO = 2
+
[docs]GREATER_THAN = 3
+
[docs]EQUAL_TO = 4
+
[docs]NOT_EQUAL_TO = 5
+ + + +_ARGUMENT = _descriptor.Descriptor( + name='Argument', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.Argument', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='string_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.Argument.string_value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='long_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.Argument.long_value', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='bool_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.Argument.bool_value', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.Argument.value', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=115, + serialized_end=202, +) + + +_CALLREQUEST = _descriptor.Descriptor( + name='CallRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallRequest.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='arguments', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallRequest.arguments', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=204, + serialized_end=301, +) + + +_RETURNVALUE = _descriptor.Descriptor( + name='ReturnValue', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='string_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue.string_value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='long_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue.long_value', index=1, + number=2, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='bool_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue.bool_value', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue.value', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=303, + serialized_end=393, +) + + +_CALLRESPONSE = _descriptor.Descriptor( + name='CallResponse', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='return_value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallResponse.return_value', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=395, + serialized_end=485, +) + + +_LISTENREQUEST = _descriptor.Descriptor( + name='ListenRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest.id', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='slots', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest.slots', index=1, + number=2, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='code', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest.code', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='class_name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest.class_name', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=487, + serialized_end=563, +) + + +_HANDLEDREQUEST = _descriptor.Descriptor( + name='HandledRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.HandledRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='time', full_name='koapy.backend.kiwoom_open_api_plus.grpc.HandledRequest.time', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=565, + serialized_end=595, +) + + +_STOPLISTENREQUEST = _descriptor.Descriptor( + name='StopListenRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.StopListenRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='time', full_name='koapy.backend.kiwoom_open_api_plus.grpc.StopListenRequest.time', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=597, + serialized_end=630, +) + + +_BIDIRECTIONALLISTENREQUEST = _descriptor.Descriptor( + name='BidirectionalListenRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='listen_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest.listen_request', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='handled_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest.handled_request', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='stop_listen_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest.stop_listen_request', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest.request', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=633, + serialized_end=929, +) + + +_SINGLEDATA = _descriptor.Descriptor( + name='SingleData', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.SingleData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='names', full_name='koapy.backend.kiwoom_open_api_plus.grpc.SingleData.names', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='values', full_name='koapy.backend.kiwoom_open_api_plus.grpc.SingleData.values', index=1, + number=2, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=931, + serialized_end=974, +) + + +_REPEATEDSTRING = _descriptor.Descriptor( + name='RepeatedString', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.RepeatedString', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='values', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RepeatedString.values', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=976, + serialized_end=1008, +) + + +_MULTIDATA = _descriptor.Descriptor( + name='MultiData', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.MultiData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='names', full_name='koapy.backend.kiwoom_open_api_plus.grpc.MultiData.names', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='values', full_name='koapy.backend.kiwoom_open_api_plus.grpc.MultiData.values', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1010, + serialized_end=1109, +) + + +_LISTENRESPONSE = _descriptor.Descriptor( + name='ListenResponse', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='arguments', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse.arguments', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='single_data', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse.single_data', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='multi_data', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse.multi_data', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1112, + serialized_end=1358, +) + + +_CALLANDLISTENREQUEST = _descriptor.Descriptor( + name='CallAndListenRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='call_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest.call_request', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='listen_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest.listen_request', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1361, + serialized_end=1539, +) + + +_CALLANDLISTENRESPONSE = _descriptor.Descriptor( + name='CallAndListenResponse', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='call_response', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse.call_response', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='listen_response', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse.listen_response', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='response', full_name='koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse.response', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=1542, + serialized_end=1741, +) + + +_LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY = _descriptor.Descriptor( + name='AccountPasswordsEntry', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1958, + serialized_end=2013, +) + +_LOGINCREDENTIALS = _descriptor.Descriptor( + name='LoginCredentials', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='user_id', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.user_id', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='user_password', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.user_password', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='cert_password', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.cert_password', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='is_simulation', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.is_simulation', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='account_passwords', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.account_passwords', index=4, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1744, + serialized_end=2013, +) + + +_LOGINREQUEST = _descriptor.Descriptor( + name='LoginRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='credentials', full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoginRequest.credentials', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2015, + serialized_end=2109, +) + + +_REALREQUESTFLAGS = _descriptor.Descriptor( + name='RealRequestFlags', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='infer_fids', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags.infer_fids', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='readable_names', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags.readable_names', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fast_parse', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags.fast_parse', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2111, + serialized_end=2193, +) + + +_REALREQUEST = _descriptor.Descriptor( + name='RealRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='screen_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest.screen_no', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='code_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest.code_list', index=1, + number=2, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fid_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest.fid_list', index=2, + number=3, type=5, cpp_type=1, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='opt_type', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest.opt_type', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flags', full_name='koapy.backend.kiwoom_open_api_plus.grpc.RealRequest.flags', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2196, + serialized_end=2357, +) + + +_TRANSACTIONSTOPCONDITION = _descriptor.Descriptor( + name='TransactionStopCondition', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='comparator', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition.comparator', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2360, + serialized_end=2511, +) + + +_TRANSACTIONREQUEST_INPUTSENTRY = _descriptor.Descriptor( + name='InputsEntry', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='value', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2857, + serialized_end=2902, +) + +_TRANSACTIONREQUEST = _descriptor.Descriptor( + name='TransactionRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='request_name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.request_name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='transaction_code', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.transaction_code', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='screen_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.screen_no', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='inputs', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.inputs', index=3, + number=4, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='stop_condition', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.stop_condition', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flags', full_name='koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.flags', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_TRANSACTIONREQUEST_INPUTSENTRY, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2514, + serialized_end=2902, +) + + +_ORDERSUBSCRIPTIONTARGET = _descriptor.Descriptor( + name='OrderSubscriptionTarget', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='RET', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget.RET', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='TR', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget.TR', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='REAL', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget.REAL', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='MSG', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget.MSG', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='CHEJAN', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget.CHEJAN', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2904, + serialized_end=2997, +) + + +_ORDERREQUEST = _descriptor.Descriptor( + name='OrderRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='request_name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.request_name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='screen_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.screen_no', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='account_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.account_no', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='order_type', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.order_type', index=3, + number=4, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='code', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.code', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='quantity', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.quantity', index=5, + number=6, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='price', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.price', index=6, + number=7, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='quote_type', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.quote_type', index=7, + number=8, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='original_order_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.original_order_no', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target', full_name='koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest.target', index=9, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3000, + serialized_end=3271, +) + + +_LOADCONDITIONREQUEST = _descriptor.Descriptor( + name='LoadConditionRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.LoadConditionRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3273, + serialized_end=3295, +) + + +_CONDITIONREQUESTFLAGS = _descriptor.Descriptor( + name='ConditionRequestFlags', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='with_info', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags.with_info', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='is_future_option', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags.is_future_option', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3297, + serialized_end=3365, +) + + +_CONDITIONREQUEST = _descriptor.Descriptor( + name='ConditionRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='screen_no', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.screen_no', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='condition_name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.condition_name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='condition_index', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.condition_index', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='search_type', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.search_type', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='request_name', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.request_name', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flags', full_name='koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest.flags', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3368, + serialized_end=3576, +) + + +_SETLOGLEVELREQUEST = _descriptor.Descriptor( + name='SetLogLevelRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='level', full_name='koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest.level', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='logger', full_name='koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest.logger', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3578, + serialized_end=3629, +) + + +_SETLOGLEVELRESPONSE = _descriptor.Descriptor( + name='SetLogLevelResponse', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3631, + serialized_end=3652, +) + + +_BIDIRECTIONALREALINITIALIZEREQUEST = _descriptor.Descriptor( + name='BidirectionalRealInitializeRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='fid_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequest.fid_list', index=0, + number=1, type=5, cpp_type=1, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='flags', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequest.flags', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3655, + serialized_end=3783, +) + + +_BIDIRECTIONALREALREGISTERREQUEST = _descriptor.Descriptor( + name='BidirectionalRealRegisterRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='code_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequest.code_list', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='fid_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequest.fid_list', index=1, + number=2, type=5, cpp_type=1, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3785, + serialized_end=3856, +) + + +_BIDIRECTIONALREALREMOVEREQUEST = _descriptor.Descriptor( + name='BidirectionalRealRemoveRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRemoveRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='code_list', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRemoveRequest.code_list', index=0, + number=1, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3858, + serialized_end=3909, +) + + +_BIDIRECTIONALREALSTOPREQUEST = _descriptor.Descriptor( + name='BidirectionalRealStopRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealStopRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3911, + serialized_end=3941, +) + + +_BIDIRECTIONALREALREQUEST = _descriptor.Descriptor( + name='BidirectionalRealRequest', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='initialize_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest.initialize_request', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='register_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest.register_request', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='remove_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest.remove_request', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='stop_request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest.stop_request', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='request', full_name='koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest.request', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=3944, + serialized_end=4385, +) + +_ARGUMENT.oneofs_by_name['value'].fields.append( + _ARGUMENT.fields_by_name['string_value']) +_ARGUMENT.fields_by_name['string_value'].containing_oneof = _ARGUMENT.oneofs_by_name['value'] +_ARGUMENT.oneofs_by_name['value'].fields.append( + _ARGUMENT.fields_by_name['long_value']) +_ARGUMENT.fields_by_name['long_value'].containing_oneof = _ARGUMENT.oneofs_by_name['value'] +_ARGUMENT.oneofs_by_name['value'].fields.append( + _ARGUMENT.fields_by_name['bool_value']) +_ARGUMENT.fields_by_name['bool_value'].containing_oneof = _ARGUMENT.oneofs_by_name['value'] +_CALLREQUEST.fields_by_name['arguments'].message_type = _ARGUMENT +_RETURNVALUE.oneofs_by_name['value'].fields.append( + _RETURNVALUE.fields_by_name['string_value']) +_RETURNVALUE.fields_by_name['string_value'].containing_oneof = _RETURNVALUE.oneofs_by_name['value'] +_RETURNVALUE.oneofs_by_name['value'].fields.append( + _RETURNVALUE.fields_by_name['long_value']) +_RETURNVALUE.fields_by_name['long_value'].containing_oneof = _RETURNVALUE.oneofs_by_name['value'] +_RETURNVALUE.oneofs_by_name['value'].fields.append( + _RETURNVALUE.fields_by_name['bool_value']) +_RETURNVALUE.fields_by_name['bool_value'].containing_oneof = _RETURNVALUE.oneofs_by_name['value'] +_CALLRESPONSE.fields_by_name['return_value'].message_type = _RETURNVALUE +_BIDIRECTIONALLISTENREQUEST.fields_by_name['listen_request'].message_type = _LISTENREQUEST +_BIDIRECTIONALLISTENREQUEST.fields_by_name['handled_request'].message_type = _HANDLEDREQUEST +_BIDIRECTIONALLISTENREQUEST.fields_by_name['stop_listen_request'].message_type = _STOPLISTENREQUEST +_BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALLISTENREQUEST.fields_by_name['listen_request']) +_BIDIRECTIONALLISTENREQUEST.fields_by_name['listen_request'].containing_oneof = _BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'] +_BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALLISTENREQUEST.fields_by_name['handled_request']) +_BIDIRECTIONALLISTENREQUEST.fields_by_name['handled_request'].containing_oneof = _BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'] +_BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALLISTENREQUEST.fields_by_name['stop_listen_request']) +_BIDIRECTIONALLISTENREQUEST.fields_by_name['stop_listen_request'].containing_oneof = _BIDIRECTIONALLISTENREQUEST.oneofs_by_name['request'] +_MULTIDATA.fields_by_name['values'].message_type = _REPEATEDSTRING +_LISTENRESPONSE.fields_by_name['arguments'].message_type = _ARGUMENT +_LISTENRESPONSE.fields_by_name['single_data'].message_type = _SINGLEDATA +_LISTENRESPONSE.fields_by_name['multi_data'].message_type = _MULTIDATA +_CALLANDLISTENREQUEST.fields_by_name['call_request'].message_type = _CALLREQUEST +_CALLANDLISTENREQUEST.fields_by_name['listen_request'].message_type = _LISTENREQUEST +_CALLANDLISTENRESPONSE.fields_by_name['call_response'].message_type = _CALLRESPONSE +_CALLANDLISTENRESPONSE.fields_by_name['listen_response'].message_type = _LISTENRESPONSE +_CALLANDLISTENRESPONSE.oneofs_by_name['response'].fields.append( + _CALLANDLISTENRESPONSE.fields_by_name['call_response']) +_CALLANDLISTENRESPONSE.fields_by_name['call_response'].containing_oneof = _CALLANDLISTENRESPONSE.oneofs_by_name['response'] +_CALLANDLISTENRESPONSE.oneofs_by_name['response'].fields.append( + _CALLANDLISTENRESPONSE.fields_by_name['listen_response']) +_CALLANDLISTENRESPONSE.fields_by_name['listen_response'].containing_oneof = _CALLANDLISTENRESPONSE.oneofs_by_name['response'] +_LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY.containing_type = _LOGINCREDENTIALS +_LOGINCREDENTIALS.fields_by_name['account_passwords'].message_type = _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY +_LOGINREQUEST.fields_by_name['credentials'].message_type = _LOGINCREDENTIALS +_REALREQUEST.fields_by_name['flags'].message_type = _REALREQUESTFLAGS +
[docs]_TRANSACTIONSTOPCONDITION.fields_by_name['comparator'].enum_type = _TRANSACTIONSTOPCONDITIONCOMPARTOR
+
[docs]_TRANSACTIONREQUEST_INPUTSENTRY.containing_type = _TRANSACTIONREQUEST
+_TRANSACTIONREQUEST.fields_by_name['inputs'].message_type = _TRANSACTIONREQUEST_INPUTSENTRY +_TRANSACTIONREQUEST.fields_by_name['stop_condition'].message_type = _TRANSACTIONSTOPCONDITION +_TRANSACTIONREQUEST.fields_by_name['flags'].message_type = _REALREQUESTFLAGS +_ORDERREQUEST.fields_by_name['target'].message_type = _ORDERSUBSCRIPTIONTARGET +_CONDITIONREQUEST.fields_by_name['flags'].message_type = _CONDITIONREQUESTFLAGS +_BIDIRECTIONALREALINITIALIZEREQUEST.fields_by_name['flags'].message_type = _REALREQUESTFLAGS +_BIDIRECTIONALREALREQUEST.fields_by_name['initialize_request'].message_type = _BIDIRECTIONALREALINITIALIZEREQUEST +_BIDIRECTIONALREALREQUEST.fields_by_name['register_request'].message_type = _BIDIRECTIONALREALREGISTERREQUEST +_BIDIRECTIONALREALREQUEST.fields_by_name['remove_request'].message_type = _BIDIRECTIONALREALREMOVEREQUEST +
[docs]_BIDIRECTIONALREALREQUEST.fields_by_name['stop_request'].message_type = _BIDIRECTIONALREALSTOPREQUEST
+_BIDIRECTIONALREALREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALREALREQUEST.fields_by_name['initialize_request']) +_BIDIRECTIONALREALREQUEST.fields_by_name['initialize_request'].containing_oneof = _BIDIRECTIONALREALREQUEST.oneofs_by_name['request'] +_BIDIRECTIONALREALREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALREALREQUEST.fields_by_name['register_request']) +_BIDIRECTIONALREALREQUEST.fields_by_name['register_request'].containing_oneof = _BIDIRECTIONALREALREQUEST.oneofs_by_name['request'] +_BIDIRECTIONALREALREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALREALREQUEST.fields_by_name['remove_request']) +_BIDIRECTIONALREALREQUEST.fields_by_name['remove_request'].containing_oneof = _BIDIRECTIONALREALREQUEST.oneofs_by_name['request'] +_BIDIRECTIONALREALREQUEST.oneofs_by_name['request'].fields.append( + _BIDIRECTIONALREALREQUEST.fields_by_name['stop_request']) +
[docs]_BIDIRECTIONALREALREQUEST.fields_by_name['stop_request'].containing_oneof = _BIDIRECTIONALREALREQUEST.oneofs_by_name['request']
+DESCRIPTOR.message_types_by_name['Argument'] = _ARGUMENT +DESCRIPTOR.message_types_by_name['CallRequest'] = _CALLREQUEST +DESCRIPTOR.message_types_by_name['ReturnValue'] = _RETURNVALUE +DESCRIPTOR.message_types_by_name['CallResponse'] = _CALLRESPONSE +DESCRIPTOR.message_types_by_name['ListenRequest'] = _LISTENREQUEST +DESCRIPTOR.message_types_by_name['HandledRequest'] = _HANDLEDREQUEST +DESCRIPTOR.message_types_by_name['StopListenRequest'] = _STOPLISTENREQUEST +DESCRIPTOR.message_types_by_name['BidirectionalListenRequest'] = _BIDIRECTIONALLISTENREQUEST +DESCRIPTOR.message_types_by_name['SingleData'] = _SINGLEDATA +DESCRIPTOR.message_types_by_name['RepeatedString'] = _REPEATEDSTRING +DESCRIPTOR.message_types_by_name['MultiData'] = _MULTIDATA +DESCRIPTOR.message_types_by_name['ListenResponse'] = _LISTENRESPONSE +DESCRIPTOR.message_types_by_name['CallAndListenRequest'] = _CALLANDLISTENREQUEST +DESCRIPTOR.message_types_by_name['CallAndListenResponse'] = _CALLANDLISTENRESPONSE +DESCRIPTOR.message_types_by_name['LoginCredentials'] = _LOGINCREDENTIALS +DESCRIPTOR.message_types_by_name['LoginRequest'] = _LOGINREQUEST +DESCRIPTOR.message_types_by_name['RealRequestFlags'] = _REALREQUESTFLAGS +DESCRIPTOR.message_types_by_name['RealRequest'] = _REALREQUEST +DESCRIPTOR.message_types_by_name['TransactionStopCondition'] = _TRANSACTIONSTOPCONDITION +DESCRIPTOR.message_types_by_name['TransactionRequest'] = _TRANSACTIONREQUEST +DESCRIPTOR.message_types_by_name['OrderSubscriptionTarget'] = _ORDERSUBSCRIPTIONTARGET +DESCRIPTOR.message_types_by_name['OrderRequest'] = _ORDERREQUEST +DESCRIPTOR.message_types_by_name['LoadConditionRequest'] = _LOADCONDITIONREQUEST +DESCRIPTOR.message_types_by_name['ConditionRequestFlags'] = _CONDITIONREQUESTFLAGS +DESCRIPTOR.message_types_by_name['ConditionRequest'] = _CONDITIONREQUEST +DESCRIPTOR.message_types_by_name['SetLogLevelRequest'] = _SETLOGLEVELREQUEST +DESCRIPTOR.message_types_by_name['SetLogLevelResponse'] = _SETLOGLEVELRESPONSE +DESCRIPTOR.message_types_by_name['BidirectionalRealInitializeRequest'] = _BIDIRECTIONALREALINITIALIZEREQUEST +DESCRIPTOR.message_types_by_name['BidirectionalRealRegisterRequest'] = _BIDIRECTIONALREALREGISTERREQUEST +DESCRIPTOR.message_types_by_name['BidirectionalRealRemoveRequest'] = _BIDIRECTIONALREALREMOVEREQUEST +DESCRIPTOR.message_types_by_name['BidirectionalRealStopRequest'] = _BIDIRECTIONALREALSTOPREQUEST +DESCRIPTOR.message_types_by_name['BidirectionalRealRequest'] = _BIDIRECTIONALREALREQUEST +DESCRIPTOR.enum_types_by_name['TransactionStopConditionCompartor'] = _TRANSACTIONSTOPCONDITIONCOMPARTOR +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +
[docs]Argument = _reflection.GeneratedProtocolMessageType('Argument', (_message.Message,), { + 'DESCRIPTOR' : _ARGUMENT, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.Argument) + })
+_sym_db.RegisterMessage(Argument) + +
[docs]CallRequest = _reflection.GeneratedProtocolMessageType('CallRequest', (_message.Message,), { + 'DESCRIPTOR' : _CALLREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.CallRequest) + })
+_sym_db.RegisterMessage(CallRequest) + +
[docs]ReturnValue = _reflection.GeneratedProtocolMessageType('ReturnValue', (_message.Message,), { + 'DESCRIPTOR' : _RETURNVALUE, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue) + })
+_sym_db.RegisterMessage(ReturnValue) + +
[docs]CallResponse = _reflection.GeneratedProtocolMessageType('CallResponse', (_message.Message,), { + 'DESCRIPTOR' : _CALLRESPONSE, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.CallResponse) + })
+_sym_db.RegisterMessage(CallResponse) + +
[docs]ListenRequest = _reflection.GeneratedProtocolMessageType('ListenRequest', (_message.Message,), { + 'DESCRIPTOR' : _LISTENREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest) + })
+_sym_db.RegisterMessage(ListenRequest) + +
[docs]HandledRequest = _reflection.GeneratedProtocolMessageType('HandledRequest', (_message.Message,), { + 'DESCRIPTOR' : _HANDLEDREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.HandledRequest) + })
+_sym_db.RegisterMessage(HandledRequest) + +
[docs]StopListenRequest = _reflection.GeneratedProtocolMessageType('StopListenRequest', (_message.Message,), { + 'DESCRIPTOR' : _STOPLISTENREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.StopListenRequest) + })
+_sym_db.RegisterMessage(StopListenRequest) + +
[docs]BidirectionalListenRequest = _reflection.GeneratedProtocolMessageType('BidirectionalListenRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALLISTENREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest) + })
+_sym_db.RegisterMessage(BidirectionalListenRequest) + +
[docs]SingleData = _reflection.GeneratedProtocolMessageType('SingleData', (_message.Message,), { + 'DESCRIPTOR' : _SINGLEDATA, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.SingleData) + })
+_sym_db.RegisterMessage(SingleData) + +
[docs]RepeatedString = _reflection.GeneratedProtocolMessageType('RepeatedString', (_message.Message,), { + 'DESCRIPTOR' : _REPEATEDSTRING, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.RepeatedString) + })
+_sym_db.RegisterMessage(RepeatedString) + +
[docs]MultiData = _reflection.GeneratedProtocolMessageType('MultiData', (_message.Message,), { + 'DESCRIPTOR' : _MULTIDATA, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.MultiData) + })
+_sym_db.RegisterMessage(MultiData) + +
[docs]ListenResponse = _reflection.GeneratedProtocolMessageType('ListenResponse', (_message.Message,), { + 'DESCRIPTOR' : _LISTENRESPONSE, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse) + })
+_sym_db.RegisterMessage(ListenResponse) + +
[docs]CallAndListenRequest = _reflection.GeneratedProtocolMessageType('CallAndListenRequest', (_message.Message,), { + 'DESCRIPTOR' : _CALLANDLISTENREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest) + })
+_sym_db.RegisterMessage(CallAndListenRequest) + +
[docs]CallAndListenResponse = _reflection.GeneratedProtocolMessageType('CallAndListenResponse', (_message.Message,), { + 'DESCRIPTOR' : _CALLANDLISTENRESPONSE, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse) + })
+_sym_db.RegisterMessage(CallAndListenResponse) + +
[docs]LoginCredentials = _reflection.GeneratedProtocolMessageType('LoginCredentials', (_message.Message,), { + + 'AccountPasswordsEntry' : _reflection.GeneratedProtocolMessageType('AccountPasswordsEntry', (_message.Message,), { + 'DESCRIPTOR' : _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry) + }) + , + 'DESCRIPTOR' : _LOGINCREDENTIALS, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials) + })
+_sym_db.RegisterMessage(LoginCredentials) +_sym_db.RegisterMessage(LoginCredentials.AccountPasswordsEntry) + +
[docs]LoginRequest = _reflection.GeneratedProtocolMessageType('LoginRequest', (_message.Message,), { + 'DESCRIPTOR' : _LOGINREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.LoginRequest) + })
+_sym_db.RegisterMessage(LoginRequest) + +
[docs]RealRequestFlags = _reflection.GeneratedProtocolMessageType('RealRequestFlags', (_message.Message,), { + 'DESCRIPTOR' : _REALREQUESTFLAGS, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags) + })
+_sym_db.RegisterMessage(RealRequestFlags) + +
[docs]RealRequest = _reflection.GeneratedProtocolMessageType('RealRequest', (_message.Message,), { + 'DESCRIPTOR' : _REALREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.RealRequest) + })
+_sym_db.RegisterMessage(RealRequest) + +
[docs]TransactionStopCondition = _reflection.GeneratedProtocolMessageType('TransactionStopCondition', (_message.Message,), { + 'DESCRIPTOR' : _TRANSACTIONSTOPCONDITION, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition) + })
+_sym_db.RegisterMessage(TransactionStopCondition) + +
[docs]TransactionRequest = _reflection.GeneratedProtocolMessageType('TransactionRequest', (_message.Message,), { + + 'InputsEntry' : _reflection.GeneratedProtocolMessageType('InputsEntry', (_message.Message,), { + 'DESCRIPTOR' : _TRANSACTIONREQUEST_INPUTSENTRY, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry) + }) + , + 'DESCRIPTOR' : _TRANSACTIONREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest) + })
+_sym_db.RegisterMessage(TransactionRequest) +_sym_db.RegisterMessage(TransactionRequest.InputsEntry) + +
[docs]OrderSubscriptionTarget = _reflection.GeneratedProtocolMessageType('OrderSubscriptionTarget', (_message.Message,), { + 'DESCRIPTOR' : _ORDERSUBSCRIPTIONTARGET, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget) + })
+_sym_db.RegisterMessage(OrderSubscriptionTarget) + +
[docs]OrderRequest = _reflection.GeneratedProtocolMessageType('OrderRequest', (_message.Message,), { + 'DESCRIPTOR' : _ORDERREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest) + })
+_sym_db.RegisterMessage(OrderRequest) + +
[docs]LoadConditionRequest = _reflection.GeneratedProtocolMessageType('LoadConditionRequest', (_message.Message,), { + 'DESCRIPTOR' : _LOADCONDITIONREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.LoadConditionRequest) + })
+_sym_db.RegisterMessage(LoadConditionRequest) + +
[docs]ConditionRequestFlags = _reflection.GeneratedProtocolMessageType('ConditionRequestFlags', (_message.Message,), { + 'DESCRIPTOR' : _CONDITIONREQUESTFLAGS, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags) + })
+_sym_db.RegisterMessage(ConditionRequestFlags) + +
[docs]ConditionRequest = _reflection.GeneratedProtocolMessageType('ConditionRequest', (_message.Message,), { + 'DESCRIPTOR' : _CONDITIONREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest) + })
+_sym_db.RegisterMessage(ConditionRequest) + +
[docs]SetLogLevelRequest = _reflection.GeneratedProtocolMessageType('SetLogLevelRequest', (_message.Message,), { + 'DESCRIPTOR' : _SETLOGLEVELREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest) + })
+_sym_db.RegisterMessage(SetLogLevelRequest) + +
[docs]SetLogLevelResponse = _reflection.GeneratedProtocolMessageType('SetLogLevelResponse', (_message.Message,), { + 'DESCRIPTOR' : _SETLOGLEVELRESPONSE, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelResponse) + })
+_sym_db.RegisterMessage(SetLogLevelResponse) + +
[docs]BidirectionalRealInitializeRequest = _reflection.GeneratedProtocolMessageType('BidirectionalRealInitializeRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALREALINITIALIZEREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequest) + })
+_sym_db.RegisterMessage(BidirectionalRealInitializeRequest) + +
[docs]BidirectionalRealRegisterRequest = _reflection.GeneratedProtocolMessageType('BidirectionalRealRegisterRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALREALREGISTERREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequest) + })
+_sym_db.RegisterMessage(BidirectionalRealRegisterRequest) + +
[docs]BidirectionalRealRemoveRequest = _reflection.GeneratedProtocolMessageType('BidirectionalRealRemoveRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALREALREMOVEREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRemoveRequest) + })
+_sym_db.RegisterMessage(BidirectionalRealRemoveRequest) + +
[docs]BidirectionalRealStopRequest = _reflection.GeneratedProtocolMessageType('BidirectionalRealStopRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALREALSTOPREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealStopRequest) + })
+_sym_db.RegisterMessage(BidirectionalRealStopRequest) + +
[docs]BidirectionalRealRequest = _reflection.GeneratedProtocolMessageType('BidirectionalRealRequest', (_message.Message,), { + 'DESCRIPTOR' : _BIDIRECTIONALREALREQUEST, + '__module__' : 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2' + # @@protoc_insertion_point(class_scope:koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest) + })
+_sym_db.RegisterMessage(BidirectionalRealRequest) + + +_LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY._options = None +_TRANSACTIONREQUEST_INPUTSENTRY._options = None + +_KIWOOMOPENAPIPLUSSERVICE = _descriptor.ServiceDescriptor( + name='KiwoomOpenApiPlusService', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=4548, + serialized_end=6506, + methods=[ + _descriptor.MethodDescriptor( + name='Call', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.Call', + index=0, + containing_service=None, + input_type=_CALLREQUEST, + output_type=_CALLRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='Listen', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.Listen', + index=1, + containing_service=None, + input_type=_LISTENREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='BidirectionalListen', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.BidirectionalListen', + index=2, + containing_service=None, + input_type=_BIDIRECTIONALLISTENREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='LoginCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.LoginCall', + index=3, + containing_service=None, + input_type=_LOGINREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='TransactionCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.TransactionCall', + index=4, + containing_service=None, + input_type=_TRANSACTIONREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='OrderCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.OrderCall', + index=5, + containing_service=None, + input_type=_ORDERREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='RealCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.RealCall', + index=6, + containing_service=None, + input_type=_REALREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='LoadConditionCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.LoadConditionCall', + index=7, + containing_service=None, + input_type=_LOADCONDITIONREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='ConditionCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.ConditionCall', + index=8, + containing_service=None, + input_type=_CONDITIONREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='BidirectionalRealCall', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.BidirectionalRealCall', + index=9, + containing_service=None, + input_type=_BIDIRECTIONALREALREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='OrderListen', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.OrderListen', + index=10, + containing_service=None, + input_type=_LISTENREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='CustomListen', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.CustomListen', + index=11, + containing_service=None, + input_type=_LISTENREQUEST, + output_type=_LISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='CustomCallAndListen', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.CustomCallAndListen', + index=12, + containing_service=None, + input_type=_CALLANDLISTENREQUEST, + output_type=_CALLANDLISTENRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='SetLogLevel', + full_name='koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService.SetLogLevel', + index=13, + containing_service=None, + input_type=_SETLOGLEVELREQUEST, + output_type=_SETLOGLEVELRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), +]) +_sym_db.RegisterServiceDescriptor(_KIWOOMOPENAPIPLUSSERVICE) + +DESCRIPTOR.services_by_name['KiwoomOpenApiPlusService'] = _KIWOOMOPENAPIPLUSSERVICE + +# @@protoc_insertion_point(module_scope) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.html new file mode 100644 index 00000000..7f87a46a --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.html @@ -0,0 +1,690 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc

+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 as koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2
+
+
+
[docs]class KiwoomOpenApiPlusServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Call = channel.unary_unary( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Call', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.FromString, + ) + self.Listen = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Listen', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.BidirectionalListen = channel.stream_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalListen', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.LoginCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoginCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.TransactionCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/TransactionCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.OrderCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.RealCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/RealCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.LoadConditionCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoadConditionCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.ConditionCall = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/ConditionCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.BidirectionalRealCall = channel.stream_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalRealCall', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.OrderListen = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderListen', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.CustomListen = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomListen', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + ) + self.CustomCallAndListen = channel.unary_stream( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomCallAndListen', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.FromString, + ) + self.SetLogLevel = channel.unary_unary( + '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/SetLogLevel', + request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.SerializeToString, + response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.FromString, + )
+ + +
[docs]class KiwoomOpenApiPlusServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + +
[docs] def Call(self, request, context): + """1. rpcs for general function calls + + unary rpc for an arbitrary function call, + can invoke arbitrary function on the server side by giving its name and arguments, + currently only simple data types like str and int are supported for arguments and return values + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def Listen(self, request, context): + """2. rpcs for listening and handling events + + server streaming rpc usually for listening events, + server will simply send stream items to client whenever event that is being listened is triggered, + client can handle those events solely on its own on client side but there is no guarantee that it will be synced with the server, + which means that event handler on the server side will not wait for the client to finish handling each event + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def BidirectionalListen(self, request_iterator, context): + """bidirectional streaming rpc usually for listening and handling events with proper callbacks, + server will send an stream item to client whenever an event is triggered and will wait for an client's ack, + so that following callbacks from the client can actually be processed inside the server's event handler context + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def LoginCall(self, request, context): + """3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns + + server streaming rpc for login/connect scenario, + would invoke Connect() and wait for OnEventConnect() event to test its success + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def TransactionCall(self, request, context): + """server streaming rpc for general transaction requests, + would invoke CommRqData() with several SetInputValue()s for a transaction request, + would wait for OnReceiveTrData() events, + would handle those events to gather results by invoking GetRepeatCnt() and GetCommData() inside, + might do additional CommRqData() and SetInputValue() inside event handler for possible consecutive lookups + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def OrderCall(self, request, context): + """server streaming rpc for making orders (buy/sell + update/cancel), + would invoke SendOrder() for submitting an order, + would wait for OnReceiveTrData() and OnReceiveChejanData() events to track its progress + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def RealCall(self, request, context): + """server streaming rpc for listening realtime data events, + certain transaction requests would also register some realtime data to be sent, + but usually would just call SetRealReg() to register desired realtime data to listen explicitly, + and would call SetRealRemove() to unregister them after done using, + would wait for OnReceiveRealData() events + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def LoadConditionCall(self, request, context): + """server streaming rpc for loading condition settings for conditioned search, + would call GetConditionLoad() and wait for OnReceiveConditionVer() event to test its success + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def ConditionCall(self, request, context): + """server streaming rpc for conditioned search (serching stocks with serveral conditions), + would call SendCondition() and wait for OnReceiveTrCondition() or OnReceiveRealCondition() based on its requested type + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def BidirectionalRealCall(self, request_iterator, context): + """4. rpcs for more complex use cases based on the previously categorized simple cases above + + bidirectional streaming rpc for listening realtime data events, + with capability of managing observation pool (what stocks, what fields to listen to) online, + those management requests would be sent over the client streaming line, + and ordinary realtime data events would be sent over the server streaming line + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def OrderListen(self, request, context): + """server streaming rpc for just listening order events (without submiting any order request compared to the simple case), + this is one-sided streaming rpc (server streaming rpc) like Listen() rpc, + so server would just send stream items with no consideration on coordination with its client + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def CustomListen(self, request, context): + """5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) + + pretty much similar to server streaming Listen() rpc, + but event handler would be instantiated dynamically based on the code given through the request + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def CustomCallAndListen(self, request, context): + """pretty much similar to server streaming XXXCall() rpcs (or even Call() rpc), + but event handler would be instantiated dynamically based on the code given through the request + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ +
[docs] def SetLogLevel(self, request, context): + """6. rpcs for other mics scenarios + + would update log level of process that this grpc server lives + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!')
+ + +
[docs]def add_KiwoomOpenApiPlusServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Call': grpc.unary_unary_rpc_method_handler( + servicer.Call, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.SerializeToString, + ), + 'Listen': grpc.unary_stream_rpc_method_handler( + servicer.Listen, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'BidirectionalListen': grpc.stream_stream_rpc_method_handler( + servicer.BidirectionalListen, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'LoginCall': grpc.unary_stream_rpc_method_handler( + servicer.LoginCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'TransactionCall': grpc.unary_stream_rpc_method_handler( + servicer.TransactionCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'OrderCall': grpc.unary_stream_rpc_method_handler( + servicer.OrderCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'RealCall': grpc.unary_stream_rpc_method_handler( + servicer.RealCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'LoadConditionCall': grpc.unary_stream_rpc_method_handler( + servicer.LoadConditionCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'ConditionCall': grpc.unary_stream_rpc_method_handler( + servicer.ConditionCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'BidirectionalRealCall': grpc.stream_stream_rpc_method_handler( + servicer.BidirectionalRealCall, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'OrderListen': grpc.unary_stream_rpc_method_handler( + servicer.OrderListen, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'CustomListen': grpc.unary_stream_rpc_method_handler( + servicer.CustomListen, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, + ), + 'CustomCallAndListen': grpc.unary_stream_rpc_method_handler( + servicer.CustomCallAndListen, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.SerializeToString, + ), + 'SetLogLevel': grpc.unary_unary_rpc_method_handler( + servicer.SetLogLevel, + request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.FromString, + response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,))
+ + + # This class is part of an EXPERIMENTAL API. +
[docs]class KiwoomOpenApiPlusService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod +
[docs] def Call(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Call', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def Listen(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Listen', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def BidirectionalListen(request_iterator, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.stream_stream(request_iterator, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalListen', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def LoginCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoginCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def TransactionCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/TransactionCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def OrderCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def RealCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/RealCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def LoadConditionCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoadConditionCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def ConditionCall(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/ConditionCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def BidirectionalRealCall(request_iterator, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.stream_stream(request_iterator, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalRealCall', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def OrderListen(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderListen', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def CustomListen(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomListen', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def CustomCallAndListen(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomCallAndListen', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ + @staticmethod +
[docs] def SetLogLevel(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/SetLogLevel', + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.SerializeToString, + koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.html new file mode 100644 index 00000000..8a19e47e --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.html @@ -0,0 +1,401 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import (
+    KiwoomOpenApiPlusTrInfo,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.list_conversion import string_to_list
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusConditionEventHandler( + KiwoomOpenApiPlusEventHandlerForGrpc, Logging +): + def __init__(self, control, request, context, screen_manager): + super().__init__(control, context) + self._request = request + self._screen_manager = screen_manager + + self._screen_no = request.screen_no + self._condition_name = request.condition_name + self._condition_index = request.condition_index + self._search_type = request.search_type + + self._request_name = request.request_name or "관심종목정보요청" + self._with_info = request.flags.with_info + self._is_future_option = request.flags.is_future_option + self._type_flag = 3 if self._is_future_option else 0 + + self._trcode = {0: "OPTKWFID", 3: "OPTFOFID"}[self._type_flag] + self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) + + if self._trinfo is None: + self.logger.error("Cannot find names for trcode %s", self._trinfo) + + self._single_names = self._trinfo.get_single_output_names() + self._multi_names = self._trinfo.get_multi_output_names() + +
[docs] def on_enter(self): + self.control.EnsureConditionLoaded() + condition_names = self.control.GetConditionNameListAsList() + assert (self._condition_index, self._condition_name) in condition_names + self._screen_no = self._screen_manager.borrow_screen(self._screen_no) + self.add_callback(self._screen_manager.return_screen, self._screen_no) + self.add_callback(self.control.DisconnectRealData, self._screen_no) + self.add_callback( + self.control.SendConditionStop, + self._screen_no, + self._condition_name, + self._condition_index, + ) + KiwoomOpenApiPlusError.try_or_raise_boolean( + self.control.RateLimitedSendCondition.async_call( + self._screen_no, + self._condition_name, + self._condition_index, + self._search_type, + ), + "Failed to send condition", + except_callback=self.observer.on_error, + )
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + if (scrnno, condition_name, condition_index) == ( + self._screen_no, + self._condition_name, + self._condition_index, + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrCondition" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = ( + codelist # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().long_value = ( + condition_index # pylint: disable=no-member + ) + response.arguments.add().long_value = prevnext # pylint: disable=no-member + + self.observer.on_next(response) # pylint: disable=no-member + + if self._with_info: + if "^" in codelist: + items = string_to_list(codelist, sep=";") + items = [string_to_list(item, sep="^") for item in items] + items = [tuple(item) for item in items] + codes = [item[0] for item in items] + else: + codes = string_to_list(codelist, sep=";") + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommKwRqData.async_call( + codelist, + 0, + len(codes), + self._type_flag, + self._request_name, + self._screen_no, + ), + except_callback=self.observer.on_error, + ) + + should_continue = str(prevnext) not in ["", "0"] + should_not_complete = ( + self._search_type == 1 or self._with_info or should_continue + ) + should_complete = not should_not_complete + + if should_complete: + self.observer.on_completed() + return + elif should_continue: + try: + raise KiwoomOpenApiPlusError("Should not reach here") + self.control.RateLimitedSendCondition.async_call( + self._screen_no, + self._condition_name, + self._condition_index, + int(prevnext), + ) # pylint: disable=unreachable + except KiwoomOpenApiPlusError as e: + self.observer.on_error(e) + return
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + if (condition_name, int(condition_index)) == ( + self._condition_name, + self._condition_index, + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealCondition" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = ( + condition_type # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_index # pylint: disable=no-member + ) + + self.observer.on_next(response) # pylint: disable=no-member + + if self._with_info: + codelist = code + codes = [code] + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommKwRqData.async_call( + codelist, + 0, + len(codes), + self._type_flag, + self._request_name, + self._screen_no, + ), + except_callback=self.observer.on_error, + )
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + if (scrnno, rqname) == (self._screen_no, self._request_name): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = ( + recordname # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + prevnext # pylint: disable=no-member + ) + + should_continue = str(prevnext) not in ["", "0"] + should_not_complete = self._search_type == 1 or should_continue + should_complete = not should_not_complete + + repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) + + assert trcode.upper() == self._trcode + + if repeat_cnt > 0: + if len(self._multi_names) == 0: + self.logger.warning( + "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" + ) + multi_names = self._multi_names + self._multi_names = self._single_names + self._single_name = multi_names + if len(self._multi_names) > 0: + rows = [ + [ + self.control.GetCommData( + trcode, recordname, i, name + ).strip() + for name in self._multi_names + ] + for i in range(repeat_cnt) + ] + response.multi_data.names.extend( + self._multi_names + ) # pylint: disable=no-member + for row in rows: + response.multi_data.values.add().values.extend( + row + ) # pylint: disable=no-member + + if len(self._single_names) > 0: + values = [ + self.control.GetCommData(trcode, recordname, 0, name).strip() + for name in self._single_names + ] + response.single_data.names.extend( + self._single_names + ) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response) # pylint: disable=no-member + + if should_complete: + self.observer.on_completed() + return + elif should_continue: + try: + raise KiwoomOpenApiPlusError("Should not reach here") + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommKwRqData.async_call( + self._codelist, + int(prevnext), + len(self._codes), + 3 if self._is_future_option else 0, + self._request_name, + self._screen_no, + ), + except_callback=self.observer.on_error, + ) # pylint: disable=unreachable + except KiwoomOpenApiPlusError as e: + self.observer.on_error(e) + return
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.html new file mode 100644 index 00000000..4fd662ac --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.html @@ -0,0 +1,159 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import (
+    KiwoomOpenApiPlusEventHandler,
+)
+
+
+
[docs]class KiwoomOpenApiPlusEventHandlerForGrpc( + KiwoomOpenApiPlusEventHandler +): # pylint: disable=abstract-method + def __init__(self, control, context): + super().__init__(control) + + self._context = context + self._context.add_callback(self.stop) + + @property +
[docs] def context(self): + return self._context
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.html new file mode 100644 index 00000000..a4dab37c --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.html @@ -0,0 +1,536 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import (
+    KiwoomOpenApiPlusRealType,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import (
+    KiwoomOpenApiPlusTrInfo,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.utils.logging.Logging import Logging
+from koapy.utils.notimplemented import isimplemented
+
+
+
[docs]class KiwoomOpenApiPlusLazyAllEventHandler( + KiwoomOpenApiPlusEventHandlerForGrpc, Logging +): +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = recordname # pylint: disable=no-member + response.arguments.add().string_value = prevnext # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealData" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = realtype # pylint: disable=no-member + response.arguments.add().string_value = realdata # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveMsg" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveChejanData" # pylint: disable=no-member + response.arguments.add().string_value = gubun # pylint: disable=no-member + response.arguments.add().long_value = itemcnt # pylint: disable=no-member + response.arguments.add().string_value = fidlist # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnEventConnect(self, errcode): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnEventConnect" # pylint: disable=no-member + response.arguments.add().long_value = errcode # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealCondition" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = ( + condition_type # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_index # pylint: disable=no-member + ) + self.observer.on_next(response)
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrCondition" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = codelist # pylint: disable=no-member + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().long_value = ( + condition_index # pylint: disable=no-member + ) + response.arguments.add().long_value = prevnext # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveConditionVer" # pylint: disable=no-member + response.arguments.add().long_value = ret # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + self.observer.on_next(response)
+ + +
[docs]class KiwoomOpenApiPlusEagerAllEventHandler( + KiwoomOpenApiPlusEventHandlerForGrpc, Logging +): +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = recordname # pylint: disable=no-member + response.arguments.add().string_value = prevnext # pylint: disable=no-member + + repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) + + trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(trcode) + + if trinfo is None: + self.logger.error("Cannot find names for trcode %s", trinfo) + + single_names = trinfo.get_single_output_names() + multi_names = trinfo.get_multi_output_names() + + if len(single_names) > 0: + values = [ + self.control.GetCommData(trcode, recordname, 0, name).strip() + for name in single_names + ] + response.single_data.names.extend(single_names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + if repeat_cnt > 0 and len(multi_names) > 0: + rows = [ + [ + self.control.GetCommData(trcode, recordname, i, name).strip() + for name in multi_names + ] + for i in range(repeat_cnt) + ] + response.multi_data.names.extend(multi_names) # pylint: disable=no-member + for row in rows: + response.multi_data.values.add().values.extend( + row + ) # pylint: disable=no-member + + self.observer.on_next(response)
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealData" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = realtype # pylint: disable=no-member + response.arguments.add().string_value = realdata # pylint: disable=no-member + + fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) + + if fids is None: + self.logger.error("Cannot find fids for realtype %s", realtype) + + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids + ] + values = [self.control.GetCommRealData(code, fid) for fid in fids] + + assert len(names) == len(values) + + response.single_data.names.extend(names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response)
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveMsg" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveChejanData" # pylint: disable=no-member + response.arguments.add().string_value = gubun # pylint: disable=no-member + response.arguments.add().long_value = itemcnt # pylint: disable=no-member + response.arguments.add().string_value = fidlist # pylint: disable=no-member + + fids = fidlist.rstrip(";") + fids = fids.split(";") if fids else [] + fids = [int(fid) for fid in fids] + + assert itemcnt == len(fids) + + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids + ] + values = [self.control.GetChejanData(fid).strip() for fid in fids] + + response.single_data.names.extend(names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response)
+ +
[docs] def OnEventConnect(self, errcode): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnEventConnect" # pylint: disable=no-member + response.arguments.add().long_value = errcode # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealCondition" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = ( + condition_type # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + condition_index # pylint: disable=no-member + ) + self.observer.on_next(response)
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrCondition" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = codelist # pylint: disable=no-member + response.arguments.add().string_value = ( + condition_name # pylint: disable=no-member + ) + response.arguments.add().long_value = ( + condition_index # pylint: disable=no-member + ) + response.arguments.add().long_value = prevnext # pylint: disable=no-member + self.observer.on_next(response)
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveConditionVer" # pylint: disable=no-member + response.arguments.add().long_value = ret # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + self.observer.on_next(response)
+ + +
[docs]class KiwoomOpenApiPlusAllEventHandler(KiwoomOpenApiPlusEagerAllEventHandler): + + pass
+ + +
[docs]class KiwoomOpenApiPlusLazySomeEventHandler(KiwoomOpenApiPlusLazyAllEventHandler): + def __init__(self, control, request, context): + super().__init__(control, context) + self._request = request + +
[docs] def slots(self): + names = self.names() + slots = [getattr(self, name) for name in names] + names_and_slots_implemented = [ + (name, slot) + for name, slot in zip(names, slots) + if isimplemented(slot) and name in self._request.slots + ] + return names_and_slots_implemented
+ + +
[docs]class KiwoomOpenApiPlusEagerSomeEventHandler(KiwoomOpenApiPlusEagerAllEventHandler): + def __init__(self, control, request, context): + super().__init__(control, context) + self._request = request + +
[docs] def slots(self): + names = self.names() + slots = [getattr(self, name) for name in names] + names_and_slots_implemented = [ + (name, slot) + for name, slot in zip(names, slots) + if isimplemented(slot) and name in self._request.slots + ] + return names_and_slots_implemented
+ + +
[docs]class KiwoomOpenApiPlusSomeEventHandler(KiwoomOpenApiPlusEagerSomeEventHandler): + + pass
+ + +
[docs]class KiwoomOpenApiPlusSomeBidirectionalEventHandler( + KiwoomOpenApiPlusLazySomeEventHandler +): + def __init__(self, control, request_iterator, context): + self._request_iterator = request_iterator + self._first_request = next(self._request_iterator) + assert self._first_request.HasField("listen_request") + self._request = request = self._first_request.listen_request + super().__init__(control, request, context) + +
[docs] def await_handled(self): + request = next(self._request_iterator) + if request.HasField("handled_request"): + pass + elif request.HasField("stop_listen_request"): + self.observer.on_completed() + else: + raise KiwoomOpenApiPlusError("Unexpected request")
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + super().OnReceiveTrData( + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ) + self.await_handled()
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + super().OnReceiveRealData(code, realtype, realdata) + self.await_handled()
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + super().OnReceiveMsg(scrnno, rqname, trcode, msg) + self.await_handled()
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + super().OnReceiveChejanData(gubun, itemcnt, fidlist) + self.await_handled()
+ +
[docs] def OnEventConnect(self, errcode): + super().OnEventConnect(errcode) + self.await_handled()
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + super().OnReceiveRealCondition( + code, condition_type, condition_name, condition_index + ) + self.await_handled()
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + super().OnReceiveTrCondition( + scrnno, codelist, condition_name, condition_index, prevnext + ) + self.await_handled()
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + super().OnReceiveConditionVer(ret, msg) + self.await_handled()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.html new file mode 100644 index 00000000..3c2ef6c6 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.html @@ -0,0 +1,344 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler

+import operator
+import re
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import (
+    KiwoomOpenApiPlusTrInfo,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.utils.itertools import chunk
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusKwTrEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): + + _num_codes_per_request = 100 + + def __init__(self, control, request, context, screen_manager): + super().__init__(control, context) + self._request = request + self._screen_manager = screen_manager + + self._rqname = request.request_name + self._trcode = request.transaction_code.upper() + self._scrnno = request.screen_no + self._inputs = request.inputs + + assert self._trcode in ["OPTKWFID", "OPTFOFID"] + + self._type_flag = {"OPTKWFID": 0, "OPTFOFID": 3}[self._trcode] + + self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) + + if self._trinfo is None: + self.logger.error("Cannot find names for trcode %s", self._trinfo) + + self._input_code = self._inputs.get("종목코드") + + self._code_list = self._input_code.rstrip(";").split(";") + self._code_lists = [ + codes for codes in chunk(self._code_list, self._num_codes_per_request) + ] + self._scrnnos = [None for _ in range(len(self._code_lists))] + self._scrnnos[0] = self._scrnno + self._scrnnos_completed = {} + + self._single_names = self._trinfo.get_single_output_names() + self._multi_names = self._trinfo.get_multi_output_names() + + stop_condition = request.stop_condition + stop_condition_is_valid = all( + [ + stop_condition is not None, + stop_condition.name is not None, + len(stop_condition.name) > 0, + stop_condition.name in self._multi_names, + ] + ) + + if stop_condition_is_valid: + column_index_to_check = self._multi_names.index(stop_condition.name) + comparator = { + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO: operator.le, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN: operator.lt, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO: operator.ge, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN: operator.gt, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO: operator.eq, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO: operator.ne, + }.get(stop_condition.comparator, operator.le) + + def is_stop_condition(row): + return comparator(row[column_index_to_check], stop_condition.value) + + else: + + def is_stop_condition(_): + return False + + self._is_stop_condition = is_stop_condition + +
[docs] def on_enter(self): + for i, scrnno in enumerate(self._scrnnos): + scrnno = self._screen_manager.borrow_screen(scrnno) + self._scrnnos[i] = scrnno + self._scrnnos_completed[scrnno] = False + for codes, scrnno in zip(self._code_lists, self._scrnnos): + self.add_callback(self._screen_manager.return_screen, scrnno) + self.add_callback(self.control.DisconnectRealData, scrnno) + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommKwRqData.async_call( + ";".join(codes), + 0, + len(codes), + self._type_flag, + self._rqname, + scrnno, + ), + except_callback=self.observer.on_error, + )
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + if (rqname, trcode) == (self._rqname, self._trcode) and scrnno in self._scrnnos: + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = ( + recordname # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + prevnext # pylint: disable=no-member + ) + + should_stop = prevnext in ["", "0"] + repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) + + if repeat_cnt > 0: + if len(self._multi_names) == 0: + self.logger.warning( + "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" + ) + multi_names = self._multi_names + self._multi_names = self._single_names + self._single_name = multi_names + if len(self._multi_names) > 0: + rows = [ + [ + self.control.GetCommData( + trcode, recordname, i, name + ).strip() + for name in self._multi_names + ] + for i in range(repeat_cnt) + ] + response.multi_data.names.extend( + self._multi_names + ) # pylint: disable=no-member + for row in rows: + if self._is_stop_condition(row): + should_stop = True + break + response.multi_data.values.add().values.extend( + row + ) # pylint: disable=no-member + + if len(self._single_names) > 0: + values = [ + self.control.GetCommData(trcode, recordname, 0, name).strip() + for name in self._single_names + ] + response.single_data.names.extend( + self._single_names + ) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response) + + if should_stop: + self._scrnnos_completed[scrnno] = True + if all(self._scrnnos_completed.values()): + self.observer.on_completed() + return + else: + try: + raise KiwoomOpenApiPlusError("Should not reach here") + except KiwoomOpenApiPlusError as e: + self.observer.on_error(e) + return
+ +
[docs] def OnEventConnect(self, errcode): + if errcode < 0: + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) + self.observer.on_error(error) + return
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): + msg_pattern = r"^[^(]+\((-?[0-9]+)\)$" + match = re.match(msg_pattern, msg) + if match: + errcode = match.group(1) + errcode = int(errcode) + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode, msg) + self.observer.on_error(error) + return
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.html new file mode 100644 index 00000000..9b5ca5f4 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.html @@ -0,0 +1,171 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+
+
+
[docs]class KiwoomOpenApiPlusLoadConditionEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc): + def __init__(self, control, context, request): + super().__init__(control, context) + self._request = request + +
[docs] def on_enter(self): + KiwoomOpenApiPlusError.try_or_raise_boolean( + self.control.GetConditionLoad(), "Failed to load condition" + )
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + if ret != 1: + error = KiwoomOpenApiPlusError(msg) + self.observer.on_error(error) + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveConditionVer" # pylint: disable=no-member + response.arguments.add().long_value = ret # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + self.observer.on_next(response) # pylint: disable=no-member + self.observer.on_completed()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.html new file mode 100644 index 00000000..74f56cbb --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.html @@ -0,0 +1,257 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler

+import datetime
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import (
+    KiwoomOpenApiPlusEventHandler,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusLoggingEventHandler(KiwoomOpenApiPlusEventHandler, Logging): +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + _datalength, + _errorcode, + _message, + _splmmsg, + ): + self.logger.debug( + "OnReceiveTrData(%r, %r, %r, %r, %r)", + scrnno, + rqname, + trcode, + recordname, + prevnext, + )
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata) + if code == "09" and realtype == "장시작시간": + signal_type = self.control.GetCommRealData(code, 215) + current_time = self.control.GetCommRealData(code, 20) + estimated_remaining_time = self.control.GetCommRealData(code, 214) + signal_type_msg = { + # 아래는 문서에서 확인 가능 + "0": "장시작전(동시호가시작,이후1분단위)", + "2": "장종료전(동시호가시작,이후1분단위)", + "3": "장시작(동시호가종료)", + "4": "장종료(동시호가종료)", + "8": "장종료(시간내용없음)", + "9": "장마감(시간내용없음)", + # 이후는 추정 + "s": "선물옵션장종료전(동시호가시작)", # 17번반복 + "a": "장후시간외종가시작", + "e": "선물옵션장종료(동시호가종료)", # 17번반복 + "b": "장후시간외종가종료", + "c": "시간외단일가시작", + "d": "시간외단일가종료", + }.get(signal_type, "알수없음") + if signal_type not in ["8", "9"]: + current_time = datetime.datetime.strptime(current_time, "%H%M%S") + else: + current_time = datetime.datetime.now() + ert = datetime.datetime.strptime(estimated_remaining_time, "%H%M%S") + estimated_remaining_time = datetime.timedelta( + hours=ert.hour, minutes=ert.minute, seconds=ert.second + ) + self.logger.debug( + "%s, %s remaining", signal_type_msg, estimated_remaining_time + )
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + """ + [OnReceiveMsg()이벤트] + + OnReceiveMsg( + BSTR sScrNo, // 화면번호 + BSTR sRQName, // 사용자 구분명 + BSTR sTrCode, // TR이름 + BSTR sMsg // 서버에서 전달하는 메시지 + ) + + 서버통신 후 수신한 메시지를 알려줍니다. + 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 + 이 코드번호로 분류하시면 안됩니다. + """ + self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg) + + if msg == "전문 처리 실패(-22)": + self.logger.warning("Server might have ended connection abruptly")
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist)
+ +
[docs] def OnEventConnect(self, errcode): + self.logger.debug("OnEventConnect(%r)", errcode)
+ +
[docs] def OnReceiveRealCondition( + self, code, condition_type, condition_name, condition_index + ): + self.logger.debug( + "OnReceiveRealCondition(%r, %r, %r, %r)", + code, + condition_type, + condition_name, + condition_index, + )
+ +
[docs] def OnReceiveTrCondition( + self, scrnno, codelist, condition_name, condition_index, prevnext + ): + self.logger.debug( + "OnReceiveTrCondition(%r, %r, %r, %r, %r)", + scrnno, + codelist, + condition_name, + condition_index, + prevnext, + )
+ +
[docs] def OnReceiveConditionVer(self, ret, msg): + self.logger.debug("OnReceiveConditionVer(%r, %r)", ret, msg)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.html new file mode 100644 index 00000000..2bba49e8 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.html @@ -0,0 +1,184 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler

+from google.protobuf.json_format import MessageToDict
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+
+
+
[docs]class KiwoomOpenApiPlusLoginEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc): + def __init__(self, control, request, context): + super().__init__(control, context) + self._request = request + + if self._request.HasField("credentials"): + self._credentials = self._request.credentials + self._credentials = MessageToDict( + self._credentials, preserving_proto_field_name=True + ) + else: + self._credentials = None + +
[docs] def on_enter(self): + if self._credentials is not None: + self.control.DisableAutoLogin() + KiwoomOpenApiPlusError.try_or_raise(self.control.CommConnect()) + self.control.LoginUsingPywinauto(self._credentials) + else: + KiwoomOpenApiPlusError.try_or_raise(self.control.CommConnect())
+ +
[docs] def OnEventConnect(self, errcode): + if errcode < 0: + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) + self.observer.on_error(error) + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnEventConnect" # pylint: disable=no-member + response.arguments.add().long_value = errcode # pylint: disable=no-member + self.observer.on_next(response) + self.observer.on_completed()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.html new file mode 100644 index 00000000..8706ece6 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.html @@ -0,0 +1,491 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler

+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import (
+    KiwoomOpenApiPlusRealType,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusBaseOrderEventHandler( + KiwoomOpenApiPlusEventHandlerForGrpc, Logging +): + def __init__(self, control, context): + super().__init__(control, context) + + self._single_names = ["주문번호"] + self._multi_names = [] + + self._is_stop_condition = lambda row: False + self._inputs = {} + + self._listen_msg = True + +
[docs] def ResponseForOnReceiveMsg(self, scrnno, rqname, trcode, msg): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveMsg" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = msg # pylint: disable=no-member + + return response
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + if self._listen_msg: + response = self.ResponseForOnReceiveMsg(scrnno, rqname, trcode, msg) + self.observer.on_next(response) + + # 아래는 개발과정에서 확인 용도 + # 키움에서도 경고하지만 메시지의 코드로 판단하는건 위험함 (게다가 모의투자만 해당) + if trcode == "KOA_NORMAL_BUY_KP_ORD": + if msg == "[00Z218] 모의투자 장종료 상태입니다": + self.logger.warning("Market is closed") + elif msg == "[00Z217] 모의투자 장시작전입니다": + self.logger.warning("Market is before opening") + elif msg == "[00Z237] 모의투자 단가를 입력하지 않는 호가입니다.": + self.logger.warning("Price is given but should not") + elif msg == "[00Z112] 모의투자 정상처리 되었습니다": + self.logger.debug("Order processed successfully") + elif trcode == "KOA_NORMAL_KP_CANCEL": + if msg == "[00Z924] 모의투자 취소수량이 취소가능수량을 초과합니다": + self.logger.warning("Not enough amount to cancel")
+ +
[docs] def ResponseForOnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = recordname # pylint: disable=no-member + response.arguments.add().string_value = prevnext # pylint: disable=no-member + + should_stop = prevnext in ["", "0"] # pylint: disable=unused-variable + repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) + + if len(self._single_names) > 0: + values = [ + self.control.GetCommData(trcode, recordname, 0, name).strip() + for name in self._single_names + ] + response.single_data.names.extend( + self._single_names + ) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + if repeat_cnt > 0 and len(self._multi_names) > 0: + rows = [ + [ + self.control.GetCommData(trcode, recordname, i, name).strip() + for name in self._multi_names + ] + for i in range(repeat_cnt) + ] + response.multi_data.names.extend( + self._multi_names + ) # pylint: disable=no-member + for row in rows: + if self._is_stop_condition(row): + should_stop = True + break + response.multi_data.values.add().values.extend( + row + ) # pylint: disable=no-member + + return response
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + order_no = self.control.GetCommData(trcode, recordname, 0, "주문번호").strip() + if order_no: + response = self.ResponseForOnReceiveTrData( + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ) + self.observer.on_next(response) + + should_stop = prevnext in ["", "0"] + if not should_stop: + self.logger.warning("Unexpected to have prevnext for order tr data.")
+ +
[docs] def ResponseForOnReceiveChejanData(self, gubun, itemcnt, fidlist): + fids = fidlist.rstrip(";") + fids = fids.split(";") if fids else [] + fids = [int(fid) for fid in fids] + + assert itemcnt == len(fids) + + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids + ] + values = [self.control.GetChejanData(fid).strip() for fid in fids] + + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveChejanData" # pylint: disable=no-member + response.arguments.add().string_value = gubun # pylint: disable=no-member + response.arguments.add().long_value = itemcnt # pylint: disable=no-member + response.arguments.add().string_value = fidlist # pylint: disable=no-member + + response.single_data.names.extend(names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + return response
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) + self.observer.on_next(response)
+ +
[docs] def OnEventConnect(self, errcode): + if errcode < 0: + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) + self.observer.on_error(error) + return
+ + +
[docs]class KiwoomOpenApiPlusAllOrderEventHandler(KiwoomOpenApiPlusBaseOrderEventHandler): + + pass
+ + +
[docs]class KiwoomOpenApiPlusOrderEventHandler( + KiwoomOpenApiPlusBaseOrderEventHandler, Logging +): + def __init__(self, control, request, context, screen_manager): + super().__init__(control, context) + + self._request = request + self._screen_manager = screen_manager + + self._rqname = request.request_name + self._scrnno = request.screen_no + self._accno = request.account_no + self._ordertype = request.order_type + self._code = request.code + self._qty = request.quantity + self._price = request.price + self._hogagb = request.quote_type + self._orgorderno = request.original_order_no + + self._order_no = None + self._should_stop = False + +
[docs] def on_enter(self): + self._scrnno = self._screen_manager.borrow_screen(self._scrnno) + self.add_callback(self._screen_manager.return_screen, self._scrnno) + self.add_callback(self.control.DisconnectRealData, self._scrnno) + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedSendOrder.async_call( + self._rqname, + self._scrnno, + self._accno, + self._ordertype, + self._code, + self._qty, + self._price, + self._hogagb, + self._orgorderno, + ), + except_callback=self.observer.on_error, + )
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + if (rqname, scrnno) == (self._rqname, self._scrnno): + response = self.ResponseForOnReceiveMsg(scrnno, rqname, trcode, msg) + self.observer.on_next(response)
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + if (rqname, scrnno) == (self._rqname, self._scrnno): + response = self.ResponseForOnReceiveTrData( + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ) + self.observer.on_next(response) + + self._order_no = self.control.GetCommData( + trcode, recordname, 0, "주문번호" + ).strip() + if not self._order_no: + e = KiwoomOpenApiPlusError("Cannot specify order no") + self.observer.on_error(e) + return + + should_stop = prevnext in ["", "0"] + if not should_stop: + self.logger.warning("Unexpected to have prevnext for order tr data.")
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + # TODO: 정정 케이스에 대해 테스트 해보지 않음 + # TODO: 취소를 취소하는 케이스 같은건 고려하지 않음 + # TODO: 서로 같은 원주문을 정정 혹은 취소하는 케이스 사이에는 이벤트 전파가 필요할지 모르겠음 + accno = self.control.GetChejanData(9201).strip() + code = self.control.GetChejanData(9001).strip() + if accno == self._accno and code.endswith( + self._code + ): # code 비교시에 앞에 prefix 가 붙어오기 때문에 endswith 으로 비교해야됨 + if gubun == "0": # 접수와 체결시 (+ 취소 확인) + order_no = self.control.GetChejanData(9203).strip() + original_order_no = self.control.GetChejanData(904).strip() + status = self.control.GetChejanData(913).strip() + scrnno = self.control.GetChejanData(920).strip() + is_last = self.control.GetChejanData(819).strip() == "1" + if order_no in [self._order_no, self._orgorderno] or self._order_no in [ + order_no, + original_order_no, + ]: + response = self.ResponseForOnReceiveChejanData( + gubun, itemcnt, fidlist + ) + self.observer.on_next(response) + if ( + order_no == self._order_no + ): # 자기 주문 처리하는 입장 OR 취소 및 정정 당한 뒤 원주문 정보를 받는 입장 + if is_last and self._should_stop: # 취소 확인 이후 원주문 정보 받고 종료 (타) + self.observer.on_completed() + return + elif status == "접수": + pass + elif status == "체결": + orders_left = self.control.GetChejanData(902).strip() + orders_left = int(orders_left) if orders_left.isdigit() else 0 + if orders_left == 0: + self._should_stop = True # 미체결수량이 더 이상 없다면 이후 잔고 이벤트 후 종료 + elif status == "확인": + self._should_stop = True # 취소 확인 이후 원주문 정보 받고 종료 (자) + else: + e = KiwoomOpenApiPlusError( + "Unexpected order status: %s" % status + ) + self.observer.on_error(e) + return + elif order_no == self._orgorderno: # 취소하는 입장에서 원주문 정보 받는 케이스 + if is_last and self._should_stop: # 취소 확인 이후 원주문 정보 받고 종료 (자) + self.observer.on_completed() + return + elif status in ["접수", "체결"]: + pass + else: + e = KiwoomOpenApiPlusError( + "Unexpected order status: %s" % status + ) + self.observer.on_error(e) + return + elif self._order_no == original_order_no: # 취소 혹은 정정 당하는 케이스 + if status == "접수": + pass + elif status == "확인": + self._should_stop = True # 취소 확인 이후 원주문 정보 받고 종료 (타) + else: + e = KiwoomOpenApiPlusError( + "Unexpected order status: %s" % status + ) + self.observer.on_error(e) + return + elif gubun == "1": # 국내주식 잔고전달 + response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) + self.observer.on_next(response) + if self._should_stop: # 미체결수량이 더 이상 없다면 잔고 이벤트 후 종료 + self.observer.on_completed() + return + elif gubun == "4": # 파생 잔고전달 + response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) + self.observer.on_next(response) + if self._should_stop: # 미체결수량이 더 이상 없다면 잔고 이벤트 후 종료 + self.observer.on_completed() + return + else: + e = KiwoomOpenApiPlusError("Unexpected gubun value: %s" % gubun) + self.observer.on_error(e) + return
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.html new file mode 100644 index 00000000..9de0a09f --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.html @@ -0,0 +1,484 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler

+import queue
+import threading
+
+from time import sleep
+
+import grpc
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import (
+    KiwoomOpenApiPlusRealType,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator import (
+    QueueBasedBufferedIterator,
+)
+from koapy.utils.itertools import chunk
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusRealEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): + + _num_codes_per_screen = 100 + _default_opt_type = "0" + + def __init__(self, control, request, context, screen_manager): + super().__init__(control, context) + self._request = request + self._screen_manager = screen_manager + + self._screen_no = request.screen_no + self._code_list = request.code_list + self._fid_list = request.fid_list + self._opt_type = request.opt_type + + self._infer_fids = request.flags.infer_fids + self._readable_names = request.flags.readable_names + self._fast_parse = request.flags.fast_parse + + self._code_lists = [ + codes for codes in chunk(self._code_list, self._num_codes_per_screen) + ] + + if len(self._screen_no) == 0: + self._screen_nos = [None for i in range(len(self._code_lists))] + elif len(self._screen_no) < len(self._code_lists): + self.logger.warning("Given screen nos are not sufficient.") + self._screen_nos = list(self._screen_no) + [ + None for i in range(len(self._code_lists) - len(self._screen_no)) + ] + else: + self._screen_nos = self._screen_no + + self._fid_list_joined = ";".join([str(fid) for fid in self._fid_list]) + self._opt_type_final = self._opt_type or self._default_opt_type + +
[docs] def on_enter(self): + for screen_no, code_list in zip(self._screen_nos, self._code_lists): + code_list_joined = ";".join(code_list) + screen_no = self._screen_manager.borrow_screen(screen_no) + self.add_callback(self._screen_manager.return_screen, screen_no) + for code in code_list: + self.add_callback( + self.control.SetRealRemove.async_call, screen_no, code + ) + KiwoomOpenApiPlusError.try_or_raise( + self.control.SetRealReg.async_call( + screen_no, + code_list_joined, + self._fid_list_joined, + self._opt_type_final, + ).result() + )
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + if code in self._code_list: + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealData" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = ( + realtype # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + realdata # pylint: disable=no-member + ) + + if self._infer_fids: + fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) + else: + fids = self._fid_list + + if self._readable_names: + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) + for fid in fids + ] + else: + names = [str(fid) for fid in fids] + + if self._infer_fids and self._fast_parse: + values = realdata.split("\t") + else: + values = [self.control.GetCommRealData(code, fid) for fid in fids] + + assert len(names) == len(values) + + response.single_data.names.extend(names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response) # pylint: disable=no-member
+ +
[docs] def OnEventConnect(self, errcode): + if errcode < 0: + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) + self.observer.on_error(error) + return
+ + +
[docs]class KiwoomOpenApiPlusBidirectionalRealEventHandler( + KiwoomOpenApiPlusRealEventHandler, Logging +): + def __init__(self, control, request_iterator, context, screen_manager): + request = KiwoomOpenApiPlusService_pb2.RealRequest() + super().__init__(control, request, context, screen_manager) + + self._request_iterator = request_iterator + self._buffered_request_iterator = QueueBasedBufferedIterator( + self._request_iterator + ) + + self._fid_list = [] + self._fid_list_joined = ";".join(str(fid) for fid in self._fid_list) + + self._screen_by_code = {} + self._code_list_by_screen = {} + self._code_list = [] + + self._request_iterator_consumer = None + self._request_iterator_consumer_should_stop = False + self._request_iterator_consumer_timeout = 2.0 + +
[docs] def register_code(self, code, fid_list=None): + if code in self._screen_by_code: + screen_no = self._screen_by_code[code] + opt_type = "1" + else: + screen_no = None + opt_type = "0" + + for ( + existing_screen_no, + screen_code_list, + ) in self._code_list_by_screen.items(): + if len(screen_code_list) < self._num_codes_per_screen: + screen_no = existing_screen_no + opt_type = "1" + break + + if screen_no is None: + screen_no = self._screen_manager.borrow_screen() + opt_type = "0" + + self._screen_by_code[code] = screen_no + self._code_list_by_screen.setdefault(screen_no, []).append(code) + self._code_list.append(code) + + if fid_list: + fid_list_joined = ";".join(str(fid) for fid in fid_list) + else: + fid_list_joined = self._fid_list_joined + + self.logger.debug( + "Registering code %s to screen %s with type %s", code, screen_no, opt_type + ) + + def try_to_register(retry=2, timeout=3.0): + retry_count = 0 + + def call(): + KiwoomOpenApiPlusError.try_or_raise( + self.control.SetRealReg.async_call( + screen_no, code, fid_list_joined, opt_type + ), + except_callback=on_error, + ) + + def on_error(e): + nonlocal retry_count + if isinstance(e, KiwoomOpenApiPlusError): + error_message = ( + f"Failed to register {code=}. Reason: {e} ({e.code})." + ) + else: + error_message = f"Failed to register {code=}. Reason: {e}." + if retry_count < retry: + retry_count += 1 + self.logger.warning( + f"{error_message} Retrying ({retry_count}/{retry}) in {timeout} ..." + ) + else: + self.logger.warning( + f"{error_message} Kiwoom server does not allow register." + ) + return + sleep(timeout) + call() + + call() + + try_to_register()
+ +
[docs] def remove_code(self, code): + if code in self._screen_by_code: + screen_no = self._screen_by_code[code] + self.logger.debug("Removing code %s from screen %s", code, screen_no) + self.control.SetRealRemove.async_call(screen_no, code) + self._screen_by_code.pop(code) + self._code_list_by_screen[screen_no].remove(code) + self._code_list.remove(code) + else: + self.logger.warning( + "Given code %s is not in managed code list and cannot be removed", code + )
+ +
[docs] def remove_all_codes(self): + code_list = list( + self._code_list + ) # copy in order to prevent "modification while iteration" + for code in code_list: + self.remove_code(code)
+ +
[docs] def remove_all_screens(self): + self.remove_all_codes() + screen_nos = list(self._code_list_by_screen.keys()) + for screen_no in screen_nos: + self.control.DisconnectRealData( + screen_no + ) # ensure although already removed in remove_all_codes() + self._screen_manager.return_screen(screen_no) + code_list = self._code_list_by_screen.pop(screen_no) + assert len(code_list) == 0
+ +
[docs] def consume_request_iterator(self): + while not self._request_iterator_consumer_should_stop: + try: + request = self._buffered_request_iterator.next( + timeout=self._request_iterator_consumer_timeout + ) + except queue.Empty: + pass + except grpc.RpcError: + break + else: + if request.HasField("register_request"): + code_list = request.register_request.code_list + fid_list = request.register_request.fid_list + for code in code_list: + self.register_code(code, fid_list) + elif request.HasField("remove_request"): + code_list = request.remove_request.code_list + for code in code_list: + self.remove_code(code) + elif request.HasField("stop_request"): + self.stop() + break + elif request.HasField("initialize_request"): + self._fid_list = request.initialize_request.fid_list + self._fid_list_joined = ";".join(str(fid) for fid in self._fid_list) + self._infer_fids = request.initialize_request.flags.infer_fids + self._infer_fids = True + self._readable_names = ( + request.initialize_request.flags.readable_names + ) + self._fast_parse = request.initialize_request.flags.fast_parse + self.remove_all_codes() + else: + raise KiwoomOpenApiPlusError("Unexpected request")
+ +
[docs] def stop_request_iterator_consumer(self): + if ( + self._request_iterator_consumer is not None + and self._request_iterator_consumer.is_alive() + ): + self._request_iterator_consumer_should_stop = True + self._request_iterator_consumer.join()
+ +
[docs] def start_request_iterator_consumer(self): + self.stop_request_iterator_consumer() + self._request_iterator_consumer_should_stop = False + self._request_iterator_consumer = threading.Thread( + target=self.consume_request_iterator, daemon=True + ) + self._request_iterator_consumer.start()
+ +
[docs] def on_enter(self): + self.start_request_iterator_consumer()
+ +
[docs] def on_exit(self, exc_type=None, exc_value=None, traceback=None): + self.stop_request_iterator_consumer() + self.remove_all_screens()
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + if code in self._code_list: + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveRealData" # pylint: disable=no-member + response.arguments.add().string_value = code # pylint: disable=no-member + response.arguments.add().string_value = ( + realtype # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + realdata # pylint: disable=no-member + ) + + if self._infer_fids: + fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) + else: + fids = self._fid_list + + if self._readable_names: + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) + for fid in fids + ] + else: + names = [str(fid) for fid in fids] + + if self._infer_fids and self._fast_parse: + values = realdata.split("\t") + else: + values = [self.control.GetCommRealData(code, fid) for fid in fids] + + assert len(names) == len(values) + + response.single_data.names.extend(names) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response) # pylint: disable=no-member
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.html new file mode 100644 index 00000000..b5e6f733 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.html @@ -0,0 +1,324 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler

+import operator
+import re
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import (
+    KiwoomOpenApiPlusTrInfo,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import (
+    KiwoomOpenApiPlusEventHandlerForGrpc,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusTrEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): + def __init__(self, control, request, context, screen_manager): + super().__init__(control, context) + self._request = request + self._screen_manager = screen_manager + + self._rqname = request.request_name + self._trcode = request.transaction_code + self._scrnno = request.screen_no + self._inputs = request.inputs + + self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) + + if self._trinfo is None: + self.logger.error("Cannot find names for trcode %s", self._trinfo) + + self._input_code = self._inputs.get("종목코드") + + self._single_names = self._trinfo.get_single_output_names() + self._multi_names = self._trinfo.get_multi_output_names() + + stop_condition = request.stop_condition + stop_condition_is_valid = ( + stop_condition is not None + and stop_condition.name is not None + and len(stop_condition.name) > 0 + and ( + stop_condition.name in self._multi_names + or stop_condition.name in self._single_names + ) + ) + + if stop_condition_is_valid: + comparator = { + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO: operator.le, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN: operator.lt, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO: operator.ge, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN: operator.gt, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO: operator.eq, + KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO: operator.ne, + }.get(stop_condition.comparator, operator.le) + + if stop_condition.name in self._multi_names: + column_index_to_check = self._multi_names.index(stop_condition.name) + else: + # if it does not have multi_names, it may use single_names instead. + column_index_to_check = self._single_names.index(stop_condition.name) + + def is_stop_condition(row): + return comparator(row[column_index_to_check], stop_condition.value) + + else: + + def is_stop_condition(_): + return False + + self._is_stop_condition = is_stop_condition + +
[docs] def on_enter(self): + self._scrnno = self._screen_manager.borrow_screen(self._scrnno) + self.add_callback(self._screen_manager.return_screen, self._scrnno) + self.add_callback(self.control.DisconnectRealData, self._scrnno) + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommRqData.async_call( + self._rqname, self._trcode, 0, self._scrnno, self._inputs + ), + except_callback=self.observer.on_error, + )
+ +
[docs] def OnReceiveTrData( + self, + scrnno, + rqname, + trcode, + recordname, + prevnext, + datalength, + errorcode, + message, + splmmsg, + ): + if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): + response = KiwoomOpenApiPlusService_pb2.ListenResponse() + response.name = "OnReceiveTrData" # pylint: disable=no-member + response.arguments.add().string_value = scrnno # pylint: disable=no-member + response.arguments.add().string_value = rqname # pylint: disable=no-member + response.arguments.add().string_value = trcode # pylint: disable=no-member + response.arguments.add().string_value = ( + recordname # pylint: disable=no-member + ) + response.arguments.add().string_value = ( + prevnext # pylint: disable=no-member + ) + + should_stop = prevnext in ["", "0"] + repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) + + if repeat_cnt > 0: + if len(self._multi_names) == 0: + self.logger.warning( + "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" + ) + self._single_names, self._multi_names = ( + self._multi_names, + self._single_names, + ) + if len(self._multi_names) > 0: + rows = [ + [ + self.control.GetCommData( + trcode, recordname, i, name + ).strip() + for name in self._multi_names + ] + for i in range(repeat_cnt) + ] + response.multi_data.names.extend( + self._multi_names + ) # pylint: disable=no-member + for row in rows: + if self._is_stop_condition(row): + should_stop = True + break + response.multi_data.values.add().values.extend( + row + ) # pylint: disable=no-member + + if len(self._single_names) > 0: + values = [ + self.control.GetCommData(trcode, recordname, 0, name).strip() + for name in self._single_names + ] + response.single_data.names.extend( + self._single_names + ) # pylint: disable=no-member + response.single_data.values.extend(values) # pylint: disable=no-member + + self.observer.on_next(response) + + if should_stop: + self.observer.on_completed() + else: + KiwoomOpenApiPlusError.try_or_raise( + self.control.RateLimitedCommRqData.async_call( + rqname, trcode, int(prevnext), scrnno, self._inputs + ), + except_callback=self.observer.on_error, + )
+ +
[docs] def OnEventConnect(self, errcode): + if errcode < 0: + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) + self.observer.on_error(error) + return
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): + msg_pattern = r"^[^(]+\((-?[0-9]+)\)$" + match = re.match(msg_pattern, msg) + if match: + errcode = match.group(1) + errcode = int(errcode) + error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode, msg) + self.observer.on_error(error) + return
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.html b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.html new file mode 100644 index 00000000..eee478a0 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.html @@ -0,0 +1,178 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto

+import subprocess
+
+from pathlib import Path
+
+
+
[docs]def compile_proto(): + proto_filename = "KiwoomOpenApiPlusService.proto" + file_path = Path(__file__) + file_dir = file_path.parent + project_dir = file_dir.parent.parent.parent.parent.parent + proto_path = project_dir + proto_filepath = ( + proto_path + / "koapy" + / "backend" + / "kiwoom_open_api_plus" + / "grpc" + / proto_filename + ) + python_out = project_dir + grpc_python_out = python_out + cmd = [ + "python", + "-m", + "grpc_tools.protoc", + "--proto_path=%s" % str(proto_path), + "--python_out=%s" % str(python_out), + "--grpc_python_out=%s" % str(grpc_python_out), + str(proto_filepath), + ] + print(" ".join(cmd)) + subprocess.check_call(cmd, cwd=project_dir)
+ + +if __name__ == "__main__": + compile_proto() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.html new file mode 100644 index 00000000..eece4018 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.html @@ -0,0 +1,307 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler

+import datetime
+import re
+
+from typing import Optional
+
+import pytz
+
+from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication import (
+    KiwoomOpenApiPlusManagerApplication,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler import (
+    QDialogHandler,
+)
+from koapy.compat.pyside2.QtCore import QObject
+from koapy.compat.pywinauto import Desktop, WindowSpecification
+from koapy.compat.pywinauto.findwindows import ElementNotFoundError
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class DialogToHandle: +
[docs] def should_handle(self, dialog: WindowSpecification) -> bool: + ...
+ +
[docs] def handle(self, dialog: WindowSpecification): + ...
+ +
[docs] def handle_if_needed(self, dialog: WindowSpecification): + if self.should_handle(dialog): + return self.handle(dialog)
+ + +
[docs]class KiwoomOpenApiPlusDialogToHandle(DialogToHandle, Logging): + @classmethod +
[docs] def should_handle_by_title(cls, dialog: WindowSpecification, title: str): + try: + cls.logger.debug("Checking dialog title") + dialog_text = dialog.wrapper_object().window_text() + except ElementNotFoundError: + cls.logger.warning("Could not find dialog to check") + else: + return dialog_text == title
+ + @classmethod +
[docs] def handle_by_clicking_button(cls, dialog: WindowSpecification): + try: + cls.logger.debug("Clicking confirm button on dialog") + dialog["Button"].click() + except ElementNotFoundError: + cls.logger.warning("Could not find dialog to confirm")
+ + @classmethod +
[docs] def handle_by_emiting_should_restart_signal( + cls, + app: KiwoomOpenApiPlusManagerApplication, + restart_type: KiwoomOpenApiPlusManagerApplication.RestartType, + ): + cls.logger.debug("Restarting based on the dialog's instruction") + app.shouldRestart.emit(restart_type)
+ + def __init__( + self, + title: Optional[str] = None, + time: Optional[datetime.time] = None, + body: Optional[str] = None, + app: Optional[KiwoomOpenApiPlusManagerApplication] = None, + restart_type: Optional[KiwoomOpenApiPlusManagerApplication.RestartType] = None, + ): + self._title = title + self._time = time + self._body = body + + self._app = app + self._restart_type = restart_type + +
[docs] def to_specification(self) -> WindowSpecification: + desktop = Desktop(allow_magic_lookup=False) + title_re = re.escape(self._title) + specification = desktop.window(title_re=title_re) + return specification
+ +
[docs] def should_handle(self, dialog: WindowSpecification) -> bool: + return self.should_handle_by_title(dialog, self._title)
+ +
[docs] def handle(self, dialog: WindowSpecification): + self.handle_by_clicking_button(dialog) + if self._restart_type is not None: + self.handle_by_emiting_should_restart_signal(self._app, self._restart_type)
+ +
[docs] def handle_if_needed(self, dialog: WindowSpecification): + if self.should_handle(dialog): + return self.handle(dialog)
+ + +
[docs]class KiwoomOpenApiPlusDialogHandler(QDialogHandler): + def __init__( + self, + app: KiwoomOpenApiPlusManagerApplication, + parent: Optional[QObject] = None, + ): + self._app = app + self._parent = parent + + kst = pytz.timezone("Asia/Seoul") + + system_check_noticie = KiwoomOpenApiPlusDialogToHandle( + title="안녕하세요. 키움증권 입니다.", + time=datetime.time(hour=4, minute=45, tzinfo=kst), + body=""" + 안녕하세요. 키움증권 입니다. + 시스템의 안정적인 운영을 위하여 + 매일 시스템 점검을 하고 있습니다. + 점검시간은 월~토요일 (05:05 ~ 05:10) + 일요일 (04:00 ~ 04:30) 까지 입니다. + 따라서 해당 시간대에는 접속단절이 될 수 있습니다. + 참고하시기 바랍니다. + """, + app=app, + ) + connection_lost = KiwoomOpenApiPlusDialogToHandle( + title="KHOpenAPI", + time=datetime.time(hour=5, minute=5, tzinfo=kst), + body=""" + 통신 연결이 끊겼습니다. 프로그램 종료후 재접속 해주시기 바랍니다. + """, + app=app, + ) + hts_reconnect_notice = KiwoomOpenApiPlusDialogToHandle( + title="[HTS 재접속 안내]", + time=datetime.time(hour=6, minute=50, tzinfo=kst), + body=""" + 안녕하세요. 키움증권입니다. + + 오전 6시 50분 이전에 접속하신 고객님께서는 + 영웅문을 재접속하여 주시기 바랍니다. + 재접속을 하지 않을 경우 거래종목 정보, 전일 거래에 + 대한 결제분 등이 반영되지 않아 실제 잔고와 차이가 + 발생할 수 있습니다. + -키움증권- + """, + app=app, + restart_type=KiwoomOpenApiPlusManagerApplication.RestartType.RESTART_AND_RESTORE, + ) + + self._dialogs_to_handle = [ + system_check_noticie, + connection_lost, + hts_reconnect_notice, + ] + self._specifications = [ + dialog.to_specification() for dialog in self._dialogs_to_handle + ] + + super().__init__(self._specifications, self._parent) + + self.readyDialog.connect(self.onReadyDialog) + +
[docs] def onReadyDialog(self, dialog: WindowSpecification): + for dialog_to_handle in self._dialogs_to_handle: + try: + # pylint: disable=unused-variable + dialog_wrapper_object = dialog.wrapper_object() + except ElementNotFoundError: + break + else: + dialog_to_handle.handle_if_needed(dialog)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.html b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.html new file mode 100644 index 00000000..099dc888 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.html @@ -0,0 +1,920 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication

+import datetime
+import os
+import sys
+
+from argparse import Namespace
+from contextlib import ExitStack, contextmanager
+from enum import Enum
+from pathlib import Path
+from subprocess import TimeoutExpired
+from threading import Timer
+from typing import List, Optional, Sequence, Tuple
+
+import grpc
+import win32api
+import win32con
+import win32job
+import win32process
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import (
+    KiwoomOpenApiPlusServiceClient,
+)
+from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication import (
+    KiwoomOpenApiPlusServerApplication,
+)
+from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler import (
+    KiwoomOpenApiPlusSignalHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor import (
+    QThreadPoolExecutor,
+)
+from koapy.cli.extensions.parser import ArgumentParser
+from koapy.cli.utils.grpc_options import server_and_client_argument_parser
+from koapy.compat.pyside2.QtCore import QProcess, QSize, QThreadPool, QUrl, Signal
+from koapy.compat.pyside2.QtGui import QDesktopServices, QIcon
+from koapy.compat.pyside2.QtWidgets import QApplication, QMenu, QSystemTrayIcon
+from koapy.config import config, get_32bit_executable
+from koapy.utils.logging import set_verbosity
+from koapy.utils.logging.pyside2.QObjectLogging import QObjectLogging
+from koapy.utils.subprocess import Popen
+
+
+
[docs]class KiwoomOpenApiPlusManagerApplicationArgumentParser(ArgumentParser): + def __init__(self): + self._parser = server_and_client_argument_parser + +
[docs] def parse_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Namespace: + return self._parser.parse_args(args, namespace)
+ +
[docs] def parse_known_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Tuple[Namespace, List[str]]: + return self._parser.parse_known_args(args, namespace)
+ + +
[docs]class KiwoomOpenApiPlusServerApplicationProcess(QProcess): + def __init__(self, args, parent=None): + super().__init__(parent) + + self._args = args + self._executable = get_32bit_executable() + self._arguments = [ + "-m", + KiwoomOpenApiPlusServerApplication.__module__, + ] + self._args + + self.setProgram(self._executable) + self.setArguments(self._arguments) + self.setProcessChannelMode(QProcess.ForwardedChannels) + + self._hJob = None + self._hProcess = None + + self.started.connect(self._onStarted) + self.finished.connect(self._onFinished) + + def _onStarted(self): + processId = self.processId() + + if processId != 0: + # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s + jobAttributes = None + jobName = "" + self._hJob = win32job.CreateJobObject(jobAttributes, jobName) + extendedInfo = win32job.QueryInformationJobObject( + self._hJob, win32job.JobObjectExtendedLimitInformation + ) + basicLimitInformation = extendedInfo["BasicLimitInformation"] + basicLimitInformation[ + "LimitFlags" + ] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE + win32job.SetInformationJobObject( + self._hJob, + win32job.JobObjectExtendedLimitInformation, + extendedInfo, + ) + desiredAccess = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA + inheritHandle = False + self._hProcess = win32api.OpenProcess( + desiredAccess, + inheritHandle, + processId, + ) + win32job.AssignProcessToJobObject(self._hJob, self._hProcess) + + def _onFinished(self): + exitCode = 0 + + if self._hProcess is not None: + try: + exitCode = win32process.GetExitCodeProcess(self._hProcess) + except win32process.error: + pass + + if self._hJob is not None: + win32job.TerminateJobObject(self._hJob, exitCode)
+ + +
[docs]class KiwoomOpenApiPlusServerApplicationSubprocess: + def __init__(self, args, parent=None): + self._args = args + self._executable = get_32bit_executable() + self._cmd = [ + self._executable, + "-m", + KiwoomOpenApiPlusServerApplication.__module__, + ] + self._args + self._proc = None + self._started = False + +
[docs] def start(self): + self._proc = Popen(self._cmd) + self._started = True
+ +
[docs] def waitForStarted(self, msecs: int = 30000) -> bool: + return self._started
+ +
[docs] def close(self): + if self._proc is not None: + self._proc.terminate()
+ +
[docs] def waitForFinished(self, msecs: int = 30000) -> bool: + if self._proc is not None: + secs = msecs / 1000 + try: + return_code = self._proc.wait(secs) + return return_code == 0 + except TimeoutExpired: + return False + return False
+ + +
[docs]class KiwoomOpenApiPlusManagerApplication(QObjectLogging): +
[docs] class ConnectionStatus(Enum): +
[docs] DISCONNECTED = 1
+
[docs] CONNECTED = 2
+ +
[docs] class ServerType(Enum): +
[docs] SIMULATION = 1
+
[docs] REAL = 2
+
[docs] UNKNOWN = 3
+ +
[docs] class RestartType(Enum): +
[docs] NO_RESTART = 1
+
[docs] RESTART_ONLY = 2
+
[docs] RESTART_AND_RESTORE = 3
+
[docs] RESTART_AND_CONNECT = 4
+
[docs] RESTART_WITH_UPDATE = 5
+
[docs] RESTART_WITH_UPDATE_AND_RESTORE = 6
+
[docs] RESTART_WITH_UPDATE_AND_CONNECT = 7
+ +
[docs] shouldRestart = Signal(RestartType)
+ + def __init__(self, args=()): + # Parse args + self._args = list(args) + self._argument_parser = KiwoomOpenApiPlusManagerApplicationArgumentParser() + ( + self._parsed_args, + self._remaining_args, + ) = self._argument_parser.parse_known_args(self._args[1:]) + + # Set verbosity level + self._verbose = self._parsed_args.verbose + set_verbosity(self._verbose) + + # Attributes for gprc client + self._host = self._parsed_args.host + self._port = self._parsed_args.port + + # Attributes for grpc client (SSL/TLS) + self._enable_ssl = self._parsed_args.enable_ssl + self._key_file = self._parsed_args.client_key_file + self._cert_file = self._parsed_args.client_cert_file + self._root_certs_file = self._parsed_args.client_root_certs_file + + # Start creating application for real + self.logger.debug("Creating manager application") + + # Create QApplication instance + self._app = QApplication.instance() or QApplication( + self._args[:1] + self._remaining_args + ) + + # Create this QObject after creating QApplication instance + super().__init__() + + # Capture certain signals and handle them accordingly + self._signal_handler = KiwoomOpenApiPlusSignalHandler(self, self) + self._signal_handler.signaled.connect(self._onSignal) + + # Capture dialogs from OpenAPI and handle them accordingly + from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler import ( + KiwoomOpenApiPlusDialogHandler, + ) + + self._dialog_handler = KiwoomOpenApiPlusDialogHandler(self, self) + + # Attributes for gprc client (ThreadPoolExecutor) + self._max_workers = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.client.max_workers", + 8, + ) + self._thread_pool = QThreadPool(self) + self._thread_pool.setMaxThreadCount(self._max_workers) + self._thread_pool_executor = QThreadPoolExecutor(self._thread_pool, self) + + # Prepare grpc client credentials if applicable + if self._enable_ssl: + root_certificates = None + if self._root_certs_file: + with open(self._root_certs_file, "rb") as f: + root_certificates = f.read() + private_key = None + if self._key_file: + with open(self._key_file, "rb") as f: + private_key = f.read() + certificate_chain = None + if self._cert_file: + with open(self._cert_file, "rb") as f: + certificate_chain = f.read() + self._credentials = grpc.ssl_channel_credentials( + root_certificates=root_certificates, + private_key=private_key, + certificate_chain=certificate_chain, + ) + else: + self._credentials = None + + # Initialize server subprocess and gprc client to the server + self._server_process = None + self._client = None + self._reinitializeServerProcessAndGrpcClient() + + # Restart server application whenever restart is required + self.shouldRestart.connect(self._onShouldRestart) + + # Create system tray icon + self._tray = self._createSystemTrayIcon() + + # Initialize tray icon menu by invoking related event handlers + self._onEventConnect(0) + + # Make tray icon visible + self._tray.show() + + # ============================================== + # Functions for server/client (re)initialization + # ============================================== + + def _closeClient(self): + self._client.close() + + def _closeClientIfExists(self): + if hasattr(self, "_client") and self._client is not None: + self._closeClient() + + def _closeServerProcess(self): + self._server_process.close() + self._server_process.waitForFinished() + + def _closeServerProcessIfExists(self): + if hasattr(self, "_server_process") and self._server_process is not None: + self._closeServerProcess() + + def _reinitializeServerProcessAndGrpcClient(self): + self._closeClientIfExists() + self._closeServerProcessIfExists() + + # Create server application subprocess and start that + self._server_process = KiwoomOpenApiPlusServerApplicationProcess( + self._args[1:], self + ) + self._server_process.start() + self._server_process.waitForStarted() + + # Create gRPC client + self._client = KiwoomOpenApiPlusServiceClient( + host=self._host, + port=self._port, + credentials=self._credentials, + thread_pool=self._thread_pool_executor, + ) + + # Wait for the client to be ready + self._client_timeout = 30 + assert self._client.is_ready(self._client_timeout), "Client is not ready" + + # Listen OnEventConnect event from OpenAPI + # and change some application states based on that + self._client.OnEventConnect.connect(self._onEventConnect) + + # ======================================= + # Functions for creating system tray icon + # ======================================= + + def _createIcon(self): + icon = QIcon() + filePath = Path(__file__) + iconDir = (filePath.parent / "../data/icon/manager").resolve() + + def addFilesForMode(icon, iconDir, mode): + icon.addFile( + str(iconDir / "favicon-16x16.png"), + QSize(16, 16), + mode, + ) + icon.addFile( + str(iconDir / "favicon-32x32.png"), + QSize(32, 32), + mode, + ) + icon.addFile( + str(iconDir / "apple-touch-icon.png"), + QSize(180, 180), + mode, + ) + icon.addFile( + str(iconDir / "android-chrome-192x192.png"), + QSize(192, 192), + mode, + ) + icon.addFile( + str(iconDir / "android-chrome-512x512.png"), + QSize(512, 512), + mode, + ) + + # Add files for each mode + addFilesForMode(icon, iconDir / "normal", QIcon.Normal) + addFilesForMode(icon, iconDir / "disabled", QIcon.Disabled) + addFilesForMode(icon, iconDir / "active", QIcon.Active) + + return icon + + def _createToolTip(self): + toolTip = "KOAPY Manager Application" + return toolTip + + def _createContextMenu(self): + menu = QMenu() + + # Section for actions related to connection and login + menu.addSection("Connection") + connectAction = menu.addAction("Login and connect") + connectAction.triggered.connect(self._onConnectActionTriggered) + showAccountWindowAction = menu.addAction("Show account window") + showAccountWindowAction.triggered.connect( + self._onShowAccountWindowActionTriggered + ) + enableAutoLoginAction = menu.addAction("Enable auto login") + enableAutoLoginAction.triggered.connect(self._onEnableAutoLoginActionTriggered) + checkForUpdateAction = menu.addAction("Check for update") + checkForUpdateAction.triggered.connect(self._onCheckForUpdateActionTriggered) + + # Section for displaying current status, should be disabled + menu.addSection("Status") + text = self._getConnectionStatusText(self.ConnectionStatus.DISCONNECTED) + self._connectionStatusAction = menu.addAction(text) + self._connectionStatusAction.setEnabled(False) + text = self._getServerTypeText(self.ServerType.UNKNOWN) + self._serverStatusAction = menu.addAction(text) + self._serverStatusAction.setEnabled(False) + + # Section for external links (koapy) + menu.addSection("Links") + iconDir = Path(__file__).parent / "../data/icon/external" + iconDir = iconDir.resolve() + icon = QIcon(str(iconDir / "readthedocs.png")) + documentationAction = menu.addAction(icon, "Documentation") + documentationAction.triggered.connect(self._openReadTheDocs) + icon = QIcon(str(iconDir / "github.png")) + githubAction = menu.addAction(icon, "Github") + githubAction.triggered.connect(self._openGithub) + + # Section for external links (kiwoom) + menu.addSection("Kiwoom Links") + openApiAction = menu.addAction("Kiwoom OpenAPI+ Home") + openApiAction.triggered.connect(self._openOpenApiHome) + openApiAction = menu.addAction("Kiwoom OpenAPI+ Document") + openApiAction.triggered.connect(self._openOpenApiDocument) + qnaAction = menu.addAction("Kiwoom OpenAPI+ Qna") + qnaAction.triggered.connect(self._openOpenApiQna) + + # Section for exit and restart + menu.addSection("Exit") + restartAction = menu.addAction("Restart") + restartAction.triggered.connect(self._onRestartActionTriggered) + exitAction = menu.addAction("Exit") + exitAction.triggered.connect(self._onExitActionTriggered) + + return menu + + def _createSystemTrayIcon(self): + tray = QSystemTrayIcon() + + self._icon = self._createIcon() + self._tooltip = self._createToolTip() + self._menu = self._createContextMenu() + + tray.setIcon(self._icon) + tray.setToolTip(self._tooltip) + tray.setContextMenu(self._menu) + + tray.activated.connect(self._onTrayIconActivated) # pylint: disable=no-member + + return tray + + # ========================================= + # Functions for controling tray icon states + # ========================================= + + def _updateTrayIconMode(self, mode: QIcon.Mode = QIcon.Normal): + icon = QIcon(self._icon.pixmap(16, mode)) + self._tray.setIcon(icon) + + def _getConnectionStatusText(self, status: ConnectionStatus): + text = { + self.ConnectionStatus.DISCONNECTED: "Status: Disconnected", + self.ConnectionStatus.CONNECTED: "Status: Connected", + }[status] + return text + + def _updateConnectionStatus(self, status: ConnectionStatus): + text = self._getConnectionStatusText(status) + self._connectionStatusAction.setText(text) + + def _getServerTypeText(self, server_type: ServerType): + text = { + self.ServerType.SIMULATION: "Server: Simulation", + self.ServerType.REAL: "Server: Real", + self.ServerType.UNKNOWN: "Server: Unknown", + }[server_type] + return text + + def _updateServerType(self, server_type: ServerType): + text = self._getServerTypeText(server_type) + self._serverStatusAction.setText(text) + + # ======================================= + # Functions for handling tray icon events + # ======================================= + + def _onTrayIconActivated(self, reason): + pass + + def _onExitActionTriggered(self): + self.exit() + + def _onRestartActionTriggered(self): + self._emitShouldRestart(self.RestartType.RESTART_AND_RESTORE) + + def _onConnectActionTriggered(self): + self._connect() + + def _onShowAccountWindowActionTriggered(self): + self._showAccountWindow() + + def _onEnableAutoLoginActionTriggered(self): + self._enableAutoLogin() + + def _onCheckForUpdateActionTriggered(self): + self._emitShouldRestart(self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE) + + def _openOpenApiHome(self): + openApiHomeUrl = "https://www.kiwoom.com/h/customer/download/VOpenApiInfoView" + url = QUrl(openApiHomeUrl) + QDesktopServices.openUrl(url) + + def _openOpenApiDocument(self): + openApiHomeUrl = "https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf" + url = QUrl(openApiHomeUrl) + QDesktopServices.openUrl(url) + + def _openOpenApiQna(self): + openApiQnaUrl = "https://www.kiwoom.com/h/common/bbs/VBbsBoardBWOAZView" + url = QUrl(openApiQnaUrl) + QDesktopServices.openUrl(url) + + def _openGithub(self): + githubUrl = "https://github.com/elbakramer/koapy" + url = QUrl(githubUrl) + QDesktopServices.openUrl(url) + + def _openReadTheDocs(self): + docUrl = "https://koapy.readthedocs.io/en/latest/" + url = QUrl(docUrl) + QDesktopServices.openUrl(url) + + # ============================== + # Functions for general behavior + # ============================== + + def _ensureConnectedAndThen(self, callback=None): + if not self._client.IsConnected(): + self.logger.debug("Connecting to OpenAPI server") + self._client.EnsureConnectedAndThen(callback) + + def _connect(self): + self._ensureConnectedAndThen() + + def _showAccountWindow(self): + self._ensureConnectedAndThen(lambda errcode: self._client.ShowAccountWindow()) + + def _enableAutoLogin(self): + self._ensureConnectedAndThen( + lambda errcode: self._client.EnsureAutoLoginEnabled() + ) + + def _emitShouldRestart(self, restart_type: Optional[RestartType] = None): + if restart_type is None: + restart_type = self.RestartType.RESTART_ONLY + self.shouldRestart.emit(restart_type) + + def _emitShouldRestartAndConnect(self): + self._emitShouldRestart(self.RestartType.RESTART_AND_CONNECT) + + def _onShouldRestart(self, restart_type: RestartType): + self._restart(restart_type) + + # =================================== + # Functions for handling other events + # =================================== + + def _onSignal(self, signal, frame): + self.logger.debug("Received %r for manager application", signal) + self.exit(signal) + + def _tryReconnect(self): + now = datetime.datetime.now() + buffer = datetime.timedelta(minutes=5) + + target = now + timediff = datetime.timedelta() + + maintanance_start_time = now.replace(hour=5, minute=5, second=0, microsecond=0) + maintanance_end_time = now.replace(hour=5, minute=10, second=0, microsecond=0) + + maintanance_start_time_sunday = now.replace( + hour=4, minute=0, second=0, microsecond=0 + ) + maintanance_end_time_sunday = now.replace( + hour=4, minute=30, second=0, microsecond=0 + ) + + is_maintanance = ( + (maintanance_start_time - buffer) < now < (maintanance_end_time + buffer) + ) + is_maintanance_sunday = ( + (maintanance_start_time_sunday - buffer) + < now + < (maintanance_end_time_sunday + buffer) + ) + is_sunday = now.weekday() == 6 + + if is_maintanance: + target = maintanance_end_time + buffer + elif is_sunday and is_maintanance_sunday: + target = maintanance_end_time_sunday + buffer + + timediff = target - now + total_seconds = timediff.total_seconds() + + if total_seconds > 0: + self.logger.warning( + "Connection lost due to maintanance, waiting until %s, then will try to reconnect", + target, + ) + # QTimer is not working, why? + # QTimer.singleShot(total_seconds * 1000, self._emitShouldRestartAndConnect) + timer = Timer(total_seconds, self._emitShouldRestartAndConnect) + timer.start() + else: + self.logger.warning( + "Connection lost unexpectedly, will try to reconnect right away" + ) + self._emitShouldRestartAndConnect() + + def _onEventConnect(self, errcode): + state = self._client.GetConnectState() + + if state == 1: + self._updateTrayIconMode(QIcon.Normal) + self._updateConnectionStatus(self.ConnectionStatus.CONNECTED) + server = self._client.GetServerGubun() + if server == "1": + self._updateServerType(self.ServerType.SIMULATION) + else: + self._updateServerType(self.ServerType.REAL) + else: + self._updateTrayIconMode(QIcon.Disabled) + self._updateConnectionStatus(self.ConnectionStatus.DISCONNECTED) + self._updateServerType(self.ServerType.UNKNOWN) + + if errcode == KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_SOCKET_CLOSED: + self.logger.error("Socket closed") + self._tryReconnect() + elif errcode == KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_CONNECT: + self.logger.error("Failed to connect") + + # ================================ + # Functions for context management + # ================================ + + def _close(self): + self._closeClient() + self._closeServerProcess() + +
[docs] def close(self): + return self._close()
+ + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + @contextmanager + def _execContext(self): + with ExitStack() as stack: + stack.enter_context(self._signal_handler) + stack.enter_context(self._dialog_handler) + stack.enter_context(self._thread_pool_executor) + stack.enter_context(self) + yield + + # ============================== + # Functions for public interface + # ============================== + + def __getattr__(self, name): + return getattr(self._app, name) + + def _exec(self): + with self._execContext(): + self.logger.debug("Started manager application") + return self._app.exec_() + + def _exit(self, return_code=0): + self.logger.debug("Exiting manager application") + return self._app.exit(return_code) + + def _isConnected(self): + return self._client.is_ready() and self._client.IsConnected() + + def _getAPIModulePath(self): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + module_path = API_MODULE_PATH + return module_path + + def _getAutoLoginDatPath(self): + module_path = self._getAPIModulePath() + autologin_dat = module_path / "system" / "Autologin.dat" + return autologin_dat + + def _isAutoLoginEnabled(self): + autologin_dat = self._getAutoLoginDatPath() + return autologin_dat.exists() + + def _disableAutoLogin(self): + self.logger.info("Disabling auto login") + autologin_dat = self._getAutoLoginDatPath() + if autologin_dat.exists(): + self.logger.info("Removing %s", autologin_dat) + os.remove(autologin_dat) + self.logger.info("Disabled auto login") + return True + else: + self.logger.info("Autologin is already disabled") + return False + + def _restart(self, restart_type: Optional[RestartType] = None): + self.logger.debug("Restarting server application") + + if restart_type is None: + restart_type = self.RestartType.RESTART_ONLY + + is_connected = self._isConnected() + is_autologin_enabled = self._isAutoLoginEnabled() + + should_connect_to_restore = ( + restart_type + in [ + self.RestartType.RESTART_AND_RESTORE, + self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE, + ] + and is_connected + ) + should_connect_anyway = restart_type in [ + self.RestartType.RESTART_AND_CONNECT, + self.RestartType.RESTART_WITH_UPDATE_AND_CONNECT, + ] + should_connect = should_connect_to_restore or should_connect_anyway + + should_update = restart_type in [ + self.RestartType.RESTART_WITH_UPDATE, + self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE, + self.RestartType.RESTART_WITH_UPDATE_AND_CONNECT, + ] + + if should_update: + self._reinitializeServerProcessAndGrpcClient() + if is_autologin_enabled: + self._disableAutoLogin() + self._client.CommConnectAndThen() + is_updated = self._client.HandleVersionUpgradeUsingPywinauto( + self._server_process.processId() + ) + if is_updated: + self._reinitializeServerProcessAndGrpcClient() + if is_autologin_enabled: + self.logger.info("Enabling auto login back") + self._enableAutoLogin() + if is_updated: + self.logger.info("Done update, enabled auto login") + else: + self.logger.info("There was no version update, enabled auto login") + else: + self._reinitializeServerProcessAndGrpcClient() + + if should_connect: + self.logger.debug("Re-establishing connection") + self._connect() + +
[docs] def exec_(self): + return self._exec()
+ +
[docs] def exit(self, return_code=0): + return self._exit(return_code)
+ +
[docs] def restart(self, restart_type: Optional[RestartType] = None): + return self._restart(restart_type)
+ +
[docs] def execAndExit(self): + code = self.exec_() + sys.exit(code)
+ + @classmethod +
[docs] def main(cls, args=None): + if args is None: + args = sys.argv + app = cls(args) + app.execAndExit()
+ + +if __name__ == "__main__": + KiwoomOpenApiPlusManagerApplication.main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.html b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.html new file mode 100644 index 00000000..26c66618 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.html @@ -0,0 +1,562 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication

+import sys
+
+from argparse import Namespace
+from contextlib import ExitStack, contextmanager
+from enum import Enum
+from pathlib import Path
+from typing import List, Optional, Sequence, Tuple
+
+import grpc
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import (
+    KiwoomOpenApiPlusQAxWidget,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer import (
+    KiwoomOpenApiPlusServiceServer,
+)
+from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler import (
+    KiwoomOpenApiPlusSignalHandler,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor import (
+    QThreadPoolExecutor,
+)
+from koapy.cli.extensions.parser import ArgumentParser
+from koapy.cli.utils.grpc_options import (
+    server_and_client_argument_parser,
+    server_argument_parser,
+)
+from koapy.compat.pyside2.QtCore import QSize, QThreadPool
+from koapy.compat.pyside2.QtGui import QIcon
+from koapy.compat.pyside2.QtWidgets import QApplication, QMenu, QSystemTrayIcon
+from koapy.config import config
+from koapy.utils.logging import set_verbosity
+from koapy.utils.logging.pyside2.QObjectLogging import QObjectLogging
+
+
+
[docs]class KiwoomOpenApiPlusServerApplicationArgumentParser(ArgumentParser): + def __init__(self): + self._server_argument_parser = server_argument_parser + self._server_and_client_argument_parser = server_and_client_argument_parser + + def _merge_results( + self, + server_namespace, + server_and_client_namespace, + server_args=None, + server_and_client_args=None, + ): + namespace = Namespace() + + # copy server namespace values + for key, value in vars(server_namespace).items(): + setattr(namespace, key, value) + + # set aliases + namespace.host = server_namespace.bind_address + + # copy fallback options to main options + if not namespace.key_file and server_and_client_namespace.server_key_file: + namespace.key_file = server_and_client_namespace.server_key_file + if not namespace.cert_file and server_and_client_namespace.server_cert_file: + namespace.cert_file = server_and_client_namespace.server_cert_file + if ( + not namespace.root_certs_file + and server_and_client_namespace.server_root_certs_file + ): + namespace.root_certs_file = ( + server_and_client_namespace.server_root_certs_file + ) + + if server_args is not None and server_and_client_args is not None: + # filter unrecognized args + unrecognized_args = [ + arg for arg in server_args if arg in server_and_client_args + ] + return namespace, unrecognized_args + else: + return namespace + +
[docs] def parse_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Namespace: + server_namespace = self._server_argument_parser.parse_args(args, namespace) + server_and_client_namespace = ( + self._server_and_client_argument_parser.parse_args(args, namespace) + ) + namespace = self._merge_results( + server_namespace, + server_and_client_namespace, + ) + return namespace
+ +
[docs] def parse_known_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Tuple[Namespace, List[str]]: + ( + server_namespace, + server_args, + ) = self._server_argument_parser.parse_known_args(args, namespace) + ( + server_and_client_namespace, + server_and_client_args, + ) = self._server_and_client_argument_parser.parse_known_args(args, namespace) + namespace, unrecognized_args = self._merge_results( + server_namespace, + server_and_client_namespace, + server_args, + server_and_client_args, + ) + return namespace, unrecognized_args
+ + +
[docs]class KiwoomOpenApiPlusServerApplication(QObjectLogging): +
[docs] class ConnectionStatus(Enum): +
[docs] DISCONNECTED = 1
+
[docs] CONNECTED = 2
+ +
[docs] class ServerType(Enum): +
[docs] SIMULATION = 1
+
[docs] REAL = 2
+
[docs] UNKNOWN = 3
+ + def __init__(self, args=()): + # Parse args + self._args = list(args) + self._argument_parser = KiwoomOpenApiPlusServerApplicationArgumentParser() + ( + self._parsed_args, + self._remaining_args, + ) = self._argument_parser.parse_known_args(self._args[1:]) + + # Set verbosity level + self._verbose = self._parsed_args.verbose + set_verbosity(self._verbose) + + # Attributes for gprc server + self._bind_address = self._parsed_args.bind_address + self._port = self._parsed_args.port + + # Attributes for grpc server (SSL/TLS) + self._key_file = self._parsed_args.key_file + self._cert_file = self._parsed_args.cert_file + self._root_certs_file = self._parsed_args.root_certs_file + self._require_client_auth = self._parsed_args.require_client_auth + + # Start creating application for real + self.logger.debug("Creating server application") + + # Create QApplication instance + self._app = QApplication.instance() or QApplication( + self._args[:1] + self._remaining_args + ) + + # Create this QObject after creating QApplication instance + super().__init__() + + # Capture certain signals and handle them accordingly + self._signal_handler = KiwoomOpenApiPlusSignalHandler(self, self) + self._signal_handler.signaled.connect(self._onSignal) + + # Attributes for gprc server (ThreadPoolExecutor) + self._max_workers = config.get_int( + "koapy.backend.kiwoom_open_api_plus.grpc.server.max_workers", + 8, + ) + self._thread_pool = QThreadPool(self) + self._thread_pool.setMaxThreadCount(self._max_workers) + self._thread_pool_executor = QThreadPoolExecutor(self._thread_pool, self) + + # Prepare grpc server credentials if applicable + if (self._key_file and self._cert_file) or self._root_certs_file: + private_key_certificate_chain_pairs = None + server_key = None + server_cert = None + if self._key_file: + with open(self._key_file, "rb") as f: + server_key = f.read() + if self._cert_file: + with open(self._cert_file, "rb") as f: + server_cert = f.read() + if server_key and server_cert: + private_key_certificate_chain_pairs = [ + (server_key, server_cert), + ] + root_certificates = None + if self._root_certs_file: + with open(self._root_certs_file, "rb") as f: + root_certificates = f.read() + require_client_auth = self._require_client_auth + self._credentials = grpc.ssl_server_credentials( + private_key_certificate_chain_pairs=private_key_certificate_chain_pairs, + root_certificates=root_certificates, + require_client_auth=require_client_auth, + ) + else: + self._credentials = None + + # Create OpenAPI control object + self._control = KiwoomOpenApiPlusQAxWidget() + + # Create gRPC server + self._server = KiwoomOpenApiPlusServiceServer( + control=self._control, + host=self._bind_address, + port=self._port, + credentials=self._credentials, + thread_pool=self._thread_pool_executor, + ) + + # Listen OnEventConnect event from OpenAPI + # and change some application states based on that + self._control.OnEventConnect.connect(self._onEventConnect) + + # Create system tray icon + self._tray = self._createSystemTrayIcon() + + # Initialize tray icon menu by invoking related event handlers + self._onEventConnect(0) + + # Make tray icon visible + self._tray.show() + + # ======================================= + # Functions for creating system tray icon + # ======================================= + + def _createIcon(self): + icon = QIcon() + filePath = Path(__file__) + iconDir = (filePath.parent / "../data/icon/server").resolve() + + def addFilesForMode(icon, iconDir, mode): + icon.addFile( + str(iconDir / "favicon-16x16.png"), + QSize(16, 16), + mode, + ) + icon.addFile( + str(iconDir / "favicon-32x32.png"), + QSize(32, 32), + mode, + ) + icon.addFile( + str(iconDir / "apple-touch-icon.png"), + QSize(180, 180), + mode, + ) + icon.addFile( + str(iconDir / "android-chrome-192x192.png"), + QSize(192, 192), + mode, + ) + icon.addFile( + str(iconDir / "android-chrome-512x512.png"), + QSize(512, 512), + mode, + ) + + # Add files for each mode + addFilesForMode(icon, iconDir / "normal", QIcon.Normal) + addFilesForMode(icon, iconDir / "disabled", QIcon.Disabled) + addFilesForMode(icon, iconDir / "active", QIcon.Active) + + return icon + + def _createToolTip(self): + toolTip = "KOAPY Server Application" + return toolTip + + def _createContextMenu(self): + menu = QMenu() + + # Section for displaying current status, should be disabled + menu.addSection("Status") + text = self._getConnectionStatusText(self.ConnectionStatus.DISCONNECTED) + self._connectionStatusAction = menu.addAction(text) + self._connectionStatusAction.setEnabled(False) + text = self._getServerTypeText(self.ServerType.UNKNOWN) + self._serverStatusAction = menu.addAction(text) + self._serverStatusAction.setEnabled(False) + + # Exit button + menu.addSection("Exit") + exitAction = menu.addAction("Exit") + exitAction.triggered.connect(self._onExitButtonClicked) + + return menu + + def _createSystemTrayIcon(self): + tray = QSystemTrayIcon() + + self._icon = self._createIcon() + self._tooltip = self._createToolTip() + self._menu = self._createContextMenu() + + tray.setIcon(self._icon) + tray.setToolTip(self._tooltip) + tray.setContextMenu(self._menu) + + tray.activated.connect(self._onTrayIconActivated) # pylint: disable=no-member + + return tray + + # ========================================= + # Functions for controling tray icon states + # ========================================= + + def _updateTrayIconMode(self, mode: QIcon.Mode = QIcon.Normal): + icon = QIcon(self._icon.pixmap(16, mode)) + self._tray.setIcon(icon) + + def _getConnectionStatusText(self, status: ConnectionStatus): + text = { + self.ConnectionStatus.DISCONNECTED: "Status: Disconnected", + self.ConnectionStatus.CONNECTED: "Status: Connected", + }[status] + return text + + def _updateConnectionStatus(self, status: ConnectionStatus): + text = self._getConnectionStatusText(status) + self._connectionStatusAction.setText(text) + + def _getServerTypeText(self, server_type: ServerType): + text = { + self.ServerType.SIMULATION: "Server: Simulation", + self.ServerType.REAL: "Server: Real", + self.ServerType.UNKNOWN: "Server: Unknown", + }[server_type] + return text + + def _updateServerType(self, server_type: ServerType): + text = self._getServerTypeText(server_type) + self._serverStatusAction.setText(text) + + # ======================================= + # Functions for handling tray icon events + # ======================================= + + def _onTrayIconActivated(self, reason): + if reason == QSystemTrayIcon.DoubleClick: + self._control.showNormal() + self._control.activateWindow() + + def _onExitButtonClicked(self): + self.exit() + + # =================================== + # Functions for handling other events + # =================================== + + def _onSignal(self, signal, frame): + self.logger.debug("Received %r for server application ", signal) + self.exit(signal) + + def _onEventConnect(self, errcode): + state = self._control.GetConnectState() + if state == 1: + self._updateTrayIconMode(QIcon.Normal) + self._updateConnectionStatus(self.ConnectionStatus.CONNECTED) + server = self._control.GetServerGubun() + if server == "1": + self._updateServerType(self.ServerType.SIMULATION) + else: + self._updateServerType(self.ServerType.REAL) + else: + self._updateTrayIconMode(QIcon.Disabled) + self._updateConnectionStatus(self.ConnectionStatus.DISCONNECTED) + self._updateServerType(self.ServerType.UNKNOWN) + + # ================================ + # Functions for context management + # ================================ + + @contextmanager + def _execContext(self): + with ExitStack() as stack: + stack.enter_context(self._signal_handler) + stack.enter_context(self._thread_pool_executor) + stack.enter_context(self._server) + yield + + # ============================== + # Functions for public interface + # ============================== + + def __getattr__(self, name): + return getattr(self._app, name) + + def _exec(self): + with self._execContext(): + self.logger.debug("Started server application") + return self._app.exec_() + + def _exit(self, return_code=0): + self.logger.debug("Exiting server application") + return self._app.exit(return_code) + +
[docs] def exec_(self): + return self._exec()
+ +
[docs] def exit(self, return_code=0): + return self._exit(return_code)
+ +
[docs] def execAndExit(self): + code = self.exec_() + sys.exit(code)
+ + @classmethod +
[docs] def main(cls, args=None): + if args is None: + args = sys.argv + app = cls(args) + app.execAndExit()
+ + +if __name__ == "__main__": + KiwoomOpenApiPlusServerApplication.main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.html new file mode 100644 index 00000000..15ad50ad --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.html @@ -0,0 +1,159 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler

+import signal as signal_module
+
+from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler import (
+    QSignalHandler,
+)
+
+
+
[docs]class KiwoomOpenApiPlusSignalHandler(QSignalHandler): + def __init__(self, app, parent=None): + self._app = app + self._parent = parent + + self._signals = [ + signal_module.SIGINT, + signal_module.SIGTERM, + ] + super().__init__(self._signals, self._parent)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.html new file mode 100644 index 00000000..870ba3f7 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.html @@ -0,0 +1,168 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous

+from collections.abc import Iterator
+
+from grpc._channel import _MultiThreadedRendezvous as MultiThreadedRendezvous
+
+
+
[docs]class PipeableMultiThreadedRendezvous(Iterator): + def __init__(self, rendezvous, iterator=None): + super().__init__() + self._rendezvous = rendezvous + self._iterator = iterator or self._rendezvous + assert isinstance(self._rendezvous, MultiThreadedRendezvous) + assert isinstance(self._iterator, Iterator) + + def __next__(self): + return self._iterator.__next__() + +
[docs] def pipe(self, func): + rendezvous = self._rendezvous + iterator = func(self._iterator) + return type(self)(rendezvous, iterator)
+ + def __getattr__(self, name): + try: + return getattr(self._rendezvous, name) + except AttributeError: + return getattr(self._iterator, name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.html new file mode 100644 index 00000000..634e0631 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.html @@ -0,0 +1,187 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.list_conversion — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.list_conversion

+import collections
+
+from functools import wraps
+from inspect import signature
+
+
+
[docs]def string_to_list(s, sep=";"): + if s is None: + return s + if not isinstance(s, str) and isinstance(s, collections.abc.Iterable): + return s + return s.rstrip(sep).split(sep) if s else []
+ + +
[docs]def list_to_string(l, sep=";"): + if l is None: + return l + if isinstance(l, str): + return l + if not isinstance(l, collections.abc.Iterable): + return l + return sep.join(l) if l else ""
+ + +
[docs]def convert_list_arguments(*indices): + def decorator(f): + sig = signature(f) + names = tuple(sig.parameters.keys()) + + @wraps(f) + def wrapper(*args, **kwargs): + ba = sig.bind(*args, **kwargs) + ba.apply_defaults() + for i in indices: + if isinstance(i, int): + i = names[i] + if isinstance(i, str): + ba.arguments[i] = list_to_string(ba.arguments[i]) + args = ba.args + kwargs = ba.kwargs + return f(*args, **kwargs) + + return wrapper + + return decorator
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/module_path.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/module_path.html new file mode 100644 index 00000000..4209a24e --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/module_path.html @@ -0,0 +1,161 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.module_path — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.module_path

+import functools
+
+from pathlib import Path
+
+from deprecated import deprecated
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import (
+    API_MODULE_PATH,
+)
+
+
+@deprecated
+@functools.lru_cache()
+
[docs]def GetAPIModulePath() -> Path: + return API_MODULE_PATH
+ + +if __name__ == "__main__": + print(GetAPIModulePath()) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.html new file mode 100644 index 00000000..c160188b --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.html @@ -0,0 +1,248 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler

+import re
+
+from typing import Dict, List, Optional, Sequence, Set
+
+from koapy.compat.pyside2.QtCore import QObject, Signal
+from koapy.compat.pywinauto import Desktop, WindowSpecification
+from koapy.compat.pywinauto.findwindows import ElementNotFoundError
+from koapy.compat.pywinauto.timings import TimeoutError as PywinautoTimeoutError
+from koapy.utils.logging.pyside2.QThreadLogging import QThreadLogging
+
+
+
[docs]class QDialogHandler(QThreadLogging): + +
[docs] readyDialog = Signal(WindowSpecification)
+
[docs] notReadyDialog = Signal(WindowSpecification)
+ + def __init__( + self, + specifications: Optional[Sequence[WindowSpecification]] = None, + parent: Optional[QObject] = None, + ): + QThreadLogging.__init__(self, parent) + + self._specifications: List[WindowSpecification] = ( + specifications and list(self._specifications) or [] + ) + + self._dialogs_not_ready: Set[WindowSpecification] = set(self._specifications) + self._dialogs_ready: Set[WindowSpecification] = set() + + self._text_by_dialog: Dict[WindowSpecification, str] = {} + + self._should_stop = False + + self._timeout = 1 / len(self._dialogs_not_ready) + self._retry_interval = self._timeout / 5 + + assert self._timeout >= self._retry_interval * 2 + + @classmethod +
[docs] def from_titles(cls, titles: Sequence[str], allow_magic_lookup: bool = False): + titles_escaped = [re.escape(title) for title in titles] + desktop = Desktop(allow_magic_lookup=allow_magic_lookup) + specifications = [ + desktop.window(title_re=title_re) for title_re in titles_escaped + ] + return cls(specifications)
+ +
[docs] def get_text_of_dialog( + self, + dialog: WindowSpecification, + default: Optional[str] = None, + ): + if dialog in self._text_by_dialog: + dialog_text = self._text_by_dialog[dialog] + else: + try: + dialog_text = dialog.wrapper_object().window_text() + except ElementNotFoundError: + dialog_text = default + else: + self._text_by_dialog[dialog] = dialog_text + return dialog_text
+ +
[docs] def run(self): + while not self._should_stop: + for dialog in list(self._dialogs_not_ready): + try: + dialog.wait("ready", self._timeout, self._retry_interval) + except (PywinautoTimeoutError, ElementNotFoundError): + continue + else: + dialog_text = self.get_text_of_dialog(dialog) + self.logger.debug("Dialog found: %s", dialog_text) + self._dialogs_not_ready.remove(dialog) + self._dialogs_ready.add(dialog) + self.readyDialog.emit(dialog) + + for dialog in list(self._dialogs_ready): + try: + dialog.wait_not("ready", self._timeout, self._retry_interval) + except (PywinautoTimeoutError, ElementNotFoundError): + continue + else: + dialog_text = self.get_text_of_dialog(dialog) or "(Unknown)" + self.logger.debug("Dialog closed: %s", dialog_text) + self._dialogs_ready.remove(dialog) + self._dialogs_not_ready.add(dialog) + self.notReadyDialog.emit(dialog)
+ +
[docs] def stop(self): + self._should_stop = True
+ +
[docs] def wait_for_termination(self, timeout=None): + if timeout is not None: + return self.wait(timeout) + else: + return self.wait()
+ + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.stop() + self.wait_for_termination()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.html new file mode 100644 index 00000000..404aefcc --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.html @@ -0,0 +1,270 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler

+import signal as signal_module
+import socket
+
+from signal import Signals
+from types import FrameType
+from typing import Iterable, Optional, overload
+
+from koapy.compat.pyside2.QtCore import QObject, Signal
+from koapy.compat.pyside2.QtNetwork import QAbstractSocket
+from koapy.utils.logging.pyside2.QAbstractSocketLogging import QAbstractSocketLogging
+
+
+
[docs]class QSignalHandler(QAbstractSocketLogging): + +
[docs] signaled = Signal(Signals, FrameType)
+ + @overload + def __init__(self, signals: Iterable[Signals], parent: Optional[QObject]): + ... + + @overload + def __init__(self, parent: Optional[QObject]): + ... + + def __init__(self, *args, **kwargs): + signals: Optional[Iterable[Signals]] = None + parent: Optional[QObject] = None + + args = list(args) + kwargs = dict(kwargs) + + if len(args) > 0 and not isinstance(args[0], QObject): + signals = args.pop(0) + elif "signals" in kwargs: + signals = kwargs.pop("signals") + + if len(args) > 0: + parent = args[0] + elif "parent" in kwargs: + parent = kwargs["parent"] + + self._signals = signals + self._parent = parent + + QAbstractSocketLogging.__init__( + self, QAbstractSocket.UdpSocket, *args, **kwargs + ) + + self._old_wakeup_fd = None + self._old_signal_handlers = {} + + self._wsock, self._rsock = socket.socketpair(socket.AF_INET, socket.SOCK_STREAM) + + self.readyRead.connect(self.onReadyRead) + +
[docs] def onReadyRead(self): + # it is up to the library to remove any bytes from fd before calling poll or select again + # check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details + data = self.readData(1) + + # not actually using this, since file descriptor is used for wakeup purpose only + _signal = data[0]
+ +
[docs] def emitSignal(self, signal, frame): + signal = signal_module.Signals(signal) + self.signaled.emit(signal, frame)
+ +
[docs] def setWakeUpFileDescriptor(self, descriptor, warn_on_full_buffer=True): + old_wakeup_fd = signal_module.set_wakeup_fd( + descriptor, warn_on_full_buffer=warn_on_full_buffer + ) + # remember first time replcement only + if self._old_wakeup_fd is None: + self._old_wakeup_fd = old_wakeup_fd + return old_wakeup_fd
+ +
[docs] def restoreWakeUpFileDescrptor(self): + if self._old_wakeup_fd is not None: + old_wakeup_fd = signal_module.set_wakeup_fd(self._old_wakeup_fd) + self._old_wakeup_fd = None + return old_wakeup_fd
+ +
[docs] def setHandler(self, signal, handler): + old_handler = signal_module.signal(signal, handler) + # remember first time replcement only + if signal not in self._old_signal_handlers: + self._old_signal_handlers[signal] = old_handler + return old_handler
+ +
[docs] def restoreHandler(self, signal, default=None): + if signal in self._old_signal_handlers: + if default is None: + default = signal_module.SIG_DFL + old_handler = self._old_signal_handlers.pop(signal, default) + old_handler = signal_module.signal(signal, old_handler) + return old_handler
+ +
[docs] def restoreAllHandlers(self): + if self._old_signal_handlers: + old_signal_handlers = dict(self._old_signal_handlers) + for signal, handler in old_signal_handlers.items(): + self.restoreHandler(signal, handler) + self._old_signal_handlers = {}
+ +
[docs] def setAll(self): + self.setSocketDescriptor(self._rsock.fileno()) + + # setting warn_on_full_buffer=False, since we are using the wakeup fd only for wakeups + # check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details + self.setWakeUpFileDescriptor(self._wsock.fileno(), warn_on_full_buffer=False) + + if self._signals: + for signal in self._signals: + self.setHandler(signal, self.emitSignal)
+ +
[docs] def restoreAll(self): + self.restoreWakeUpFileDescrptor() + self.restoreAllHandlers()
+ + def __del__(self): + self.restoreAll() + + def __enter__(self): + self.setAll() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.restoreAll()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.html new file mode 100644 index 00000000..9df15488 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.html @@ -0,0 +1,242 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor

+import atexit
+
+from concurrent.futures import Executor, Future
+from threading import RLock
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union, overload
+
+from koapy.compat.pyside2.QtCore import QObject, QRunnable, QThreadPool
+
+
+
[docs]class QThreadPoolExecutorRunnable(QRunnable): + def __init__( + self, + future: Future, + fn: Callable[..., Any], + args: Union[Tuple[Any], List[Any]], + kwargs: Dict[str, Any], + ): + super().__init__() + + self._future = future + self._fn = fn + self._args = args + self._kwargs = kwargs + +
[docs] def run(self): + # pylint: disable=broad-except,self-cls-assignment + if not self._future.set_running_or_notify_cancel(): + return + try: + result = self._fn(*self._args, **self._kwargs) + except BaseException as exc: + self._future.set_exception(exc) + # break a reference cycle with the exception 'exc' + self = None + else: + self._future.set_result(result)
+ + +
[docs]class QThreadPoolExecutor(QObject, Executor): + # pylint: disable=arguments-differ + + @overload + def __init__(self, thread_pool: QThreadPool, parent: Optional[QObject]): + ... + + @overload + def __init__(self, parent: Optional[QObject]): + ... + + def __init__(self, *args, **kwargs): + thread_pool: Optional[QThreadPool] = None + parent: Optional[QObject] = None + + args = list(args) + kwargs = dict(kwargs) + + if len(args) > 0 and isinstance(args[0], QThreadPool): + thread_pool = args.pop(0) + elif "thread_pool" in kwargs: + thread_pool = kwargs.pop("thread_pool") + + if len(args) > 0: + parent = args[0] + elif "parent" in kwargs: + parent = kwargs["parent"] + + if thread_pool is None: + thread_pool = QThreadPool(self) + + self._thread_pool = thread_pool + self._parent = parent + + QObject.__init__(self, *args, **kwargs) + Executor.__init__(self) + + self._shutdown = False + self._shutdown_lock = RLock() + + atexit.register(self.shutdown) + + def __del__(self): + atexit.unregister(self.shutdown) + +
[docs] def submit(self, fn, *args, **kwargs): + with self._shutdown_lock: + if self._shutdown: + raise RuntimeError("Cannot schedule new futures after shutdown") + future = Future() + runnable = QThreadPoolExecutorRunnable(future, fn, args, kwargs) + runnable.setAutoDelete(True) + self._thread_pool.start(runnable) + return future
+ +
[docs] def shutdown(self, wait=True, cancel_futures=False): + with self._shutdown_lock: + self._shutdown = True + if cancel_futures: + self._thread_pool.clear() + if wait: + self._thread_pool.waitForDone()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.html new file mode 100644 index 00000000..9f7e4dd6 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.html @@ -0,0 +1,194 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator

+import sys
+import threading
+
+from queue import Queue
+
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator import (
+    BufferedQueueIterator,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class QueueBasedBufferedIterator(BufferedQueueIterator, Logging): + + _check_timeout = 1 + _default_maxsize = 10 + + def __init__(self, iterator, queue=None, maxsize=None): + if queue is None: + if maxsize is None: + maxsize = self._default_maxsize + queue = Queue(maxsize) + + self._iterator = iterator + self._queue = queue + self._maxsize = maxsize + self._exc_info = None + + super().__init__(self._queue) + + self._thread = threading.Thread(target=self._consume_iterator, daemon=True) + self._thread.start() + + def _consume_iterator(self): + try: + for item in self._iterator: + self._queue.put(item) + except Exception: # pylint: disable=broad-except + self.logger.exception("Exception raised while consuming iterator") + self._exc_info = sys.exc_info() + +
[docs] def next(self, block=True, timeout=None): + try: + item = super().next(block, timeout) + except StopIteration as e: + if self._exc_info is not None: + raise self._exc_info[1] from e + else: + raise e + else: + if self._exc_info is not None: + raise self._exc_info[1] + return item
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.html new file mode 100644 index 00000000..2236a62d --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.html @@ -0,0 +1,209 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver

+from queue import Empty, Queue
+
+from rx.core.typing import Observer
+
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator import (
+    BufferedQueueIterator,
+)
+
+
+
[docs]class QueueBasedIterableObserverIterator(BufferedQueueIterator): + def __init__(self, queue, sentinel): + self._queue = queue + self._sentinel = sentinel + super().__init__(self._queue) + +
[docs] def next(self, block=True, timeout=None): + value, error = super().next(block, timeout) + if value == self._sentinel: + raise StopIteration + elif error is not None and isinstance(error, Exception): + raise error + return value
+ +
[docs] def head(self): + value, error = super().head() + if value == self._sentinel: + raise Empty + elif error is not None and isinstance(error, Exception): + raise error + return value
+ + +
[docs]class QueueBasedIterableObserver(Observer): + + _default_maxsize = 0 + _queue_get_timeout = 2 + + def __init__(self, queue=None, maxsize=None): + if queue is None: + if maxsize is None: + maxsize = self._default_maxsize + queue = Queue(maxsize) + + self._queue = queue + self._maxsize = maxsize + self._sentinel = object() + + self._iterator = QueueBasedIterableObserverIterator(self._queue, self._sentinel) + + @property +
[docs] def queue(self): + return self._queue
+ +
[docs] def on_next(self, value): + self._queue.put((value, None))
+ +
[docs] def on_error(self, error): + self._queue.put((None, error))
+ +
[docs] def on_completed(self): + self._queue.put((self._sentinel, None))
+ + def __iter__(self): + return self._iterator + +
[docs] def stop(self): + return self._iterator.stop()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.html b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.html new file mode 100644 index 00000000..8c2964ae --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.html @@ -0,0 +1,225 @@ + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator

+import atexit
+
+from queue import Empty
+
+
+
[docs]class QueueIterator: + + _check_timeout = 1 + + def __init__(self, queue): + self._queue = queue + self._should_stop = False + + atexit.register(self.stop) + + def __del__(self): + atexit.unregister(self.stop) + + @property +
[docs] def queue(self): + return self._queue
+ +
[docs] def next(self, block=True, timeout=None): + if block and timeout is None: + timeout = self._check_timeout + while not self._should_stop: + try: + item = self._queue.get(block=block, timeout=timeout) + except Empty: + pass + else: + self._queue.task_done() + return item + raise StopIteration + else: + item = self._queue.get(block=block, timeout=timeout) + self._queue.task_done() + return item
+ +
[docs] def next_nowait(self): + return self.next(block=False)
+ +
[docs] def has_next(self): + return not self._queue.empty()
+ + def __iter__(self): + return self + + def __next__(self): + return self.next() + +
[docs] def stop(self): + self._should_stop = True
+ +
[docs] def enable(self): + self._should_stop = False
+ + +
[docs]class BufferedQueueIterator(QueueIterator): + def __init__(self, queue): + super().__init__(queue) + + self._none = object() + self._head = self._none + +
[docs] def next(self, block=True, timeout=None): + if self._head is not self._none: + item = self._head + self._head = self._none + return item + else: + return super().next(block, timeout)
+ +
[docs] def has_next(self): + return self._head is not self._none or super().has_next()
+ +
[docs] def head(self): + if self._head is not self._none: + return self._head + else: + item = self.next_nowait() # raises queue.Empty if queue is empty + self._head = item + return self._head
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.html new file mode 100644 index 00000000..ea6b1be1 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.html @@ -0,0 +1,180 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable

+from inspect import Signature
+
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import (
+    KiwoomOpenApiWDispatchSignature,
+)
+
+
+
[docs]class KiwoomOpenApiWDynamicCallable: + def __init__(self, control, name): + self._control = control + self._name = name + self._signature = KiwoomOpenApiWDispatchSignature.from_name(self._name) + self._function = self._signature.to_pyside2_function_prototype() + self._should_test_return_type = ( + self._signature.return_annotation is not Signature.empty + ) + +
[docs] def is_valid_return_type(self, result): + if self._should_test_return_type and not isinstance( + result, self._signature.return_annotation + ): + return False + return True
+ + def __call__(self, *args, **kwargs): + ba = self._signature.bind(*args, **kwargs) + ba.apply_defaults() + result = self._control.dynamicCall(self._function, list(ba.args)) + if not self.is_valid_return_type(result): + raise TypeError( + "Return type of %s was expected for function call %s(...), but %s was found." + % ( + self._signature.return_annotation, + self._name, + type(result), + ) + ) + return result
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.html new file mode 100644 index 00000000..6e7fd7f9 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.html @@ -0,0 +1,318 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError

+from functools import wraps
+
+
+
[docs]class KiwoomOpenApiWError(Exception): + def __init__(self, message=None): + if message is not None: + super().__init__(message) + else: + super().__init__() + + self._message = message + + @property +
[docs] def message(self): + return self._message
+ + @classmethod +
[docs] def try_or_raise(cls, arg, message=None): + return KiwoomOpenApiWNegativeReturnCodeError.try_or_raise(arg, message)
+ + @classmethod +
[docs] def try_or_raise_boolean(cls, arg, message): + return KiwoomOpenApiWBooleanReturnCodeError.try_or_raise(arg, message)
+ + +
[docs]class KiwoomOpenApiWNegativeReturnCodeError(KiwoomOpenApiWError): + +
[docs] OP_ERR_NONE = 0
+
[docs] OP_ERR_NO_LOGIN = -1
+
[docs] OP_ERR_LOGIN = -100
+
[docs] OP_ERR_CONNECT = -101
+
[docs] OP_ERR_VERSION = -102
+
[docs] OP_ERR_TRCODE = -103
+
[docs] OP_ERR_NO_REGOPENAPI = -104
+
[docs] OP_ERR_SISE_OVERFLOW = -200
+
[docs] OP_ERR_ORDER_OVERFLOW = -201
+
[docs] OP_ERR_RQ_WRONG_INPUT = -202
+
[docs] OP_ERR_ORD_WRONG_INPUT = -300
+
[docs] OP_ERR_ORD_WRONG_ACCPWD = -301
+
[docs] OP_ERR_ORD_WRONG_ACCNO = -302
+
[docs] OP_ERR_ORD_WRONG_QTY200 = -303
+
[docs] OP_ERR_ORD_WRONG_QTY400 = -304
+ +
[docs] MSG_ERR_NONE = "정상처리"
+
[docs] MSG_ERR_NO_LOGIN = "미접속상태"
+
[docs] MSG_ERR_LOGIN = "로그인시 접속 실패 (아이피 오류 또는 접속정보 오류)"
+
[docs] MSG_ERR_CONNECT = "서버 접속 실패"
+
[docs] MSG_ERR_VERSION = "버전처리가 실패하였습니다."
+
[docs] MSG_ERR_TRCODE = "TrCode 가 존재하지 않습니다."
+
[docs] MSG_ERR_NO_REGOPENAPI = "해외OpenAPI 미신청"
+
[docs] MSG_ERR_SISE_OVERFLOW = "조회과부화"
+
[docs] MSG_ERR_ORDER_OVERFLOW = "주문과부화"
+
[docs] MSG_ERR_RQ_WRONG_INPUT = "조회입력값(명칭/누락) 오류"
+
[docs] MSG_ERR_ORD_WRONG_INPUT = "주문입력갑 오류"
+
[docs] MSG_ERR_ORD_WRONG_ACCPWD = "계좌비밀번호를 입력하십시오."
+
[docs] MSG_ERR_ORD_WRONG_ACCNO = "타인 계좌를 사용할 수 없습니다."
+
[docs] MSG_ERR_ORD_WRONG_QTY200 = "경고-주문수량 200개 초과"
+
[docs] MSG_ERR_ORD_WRONG_QTY400 = "제한-주문수량 400개 초과"
+ +
[docs] ERROR_MESSAGE_BY_CODE = { + OP_ERR_NONE: MSG_ERR_NONE, + OP_ERR_NO_LOGIN: MSG_ERR_NO_LOGIN, + OP_ERR_LOGIN: MSG_ERR_LOGIN, + OP_ERR_CONNECT: MSG_ERR_CONNECT, + OP_ERR_VERSION: MSG_ERR_VERSION, + OP_ERR_TRCODE: MSG_ERR_TRCODE, + OP_ERR_NO_REGOPENAPI: MSG_ERR_NO_REGOPENAPI, + OP_ERR_SISE_OVERFLOW: MSG_ERR_SISE_OVERFLOW, + OP_ERR_ORDER_OVERFLOW: MSG_ERR_ORDER_OVERFLOW, + OP_ERR_RQ_WRONG_INPUT: MSG_ERR_RQ_WRONG_INPUT, + OP_ERR_ORD_WRONG_INPUT: MSG_ERR_ORD_WRONG_INPUT, + OP_ERR_ORD_WRONG_ACCPWD: MSG_ERR_ORD_WRONG_ACCPWD, + OP_ERR_ORD_WRONG_ACCNO: MSG_ERR_ORD_WRONG_ACCNO, + OP_ERR_ORD_WRONG_QTY200: MSG_ERR_ORD_WRONG_QTY200, + OP_ERR_ORD_WRONG_QTY400: MSG_ERR_ORD_WRONG_QTY400, + }
+ + @classmethod +
[docs] def get_error_message_by_code(cls, code, default=None): + return cls.ERROR_MESSAGE_BY_CODE.get(code, default)
+ + @classmethod +
[docs] def check_code_or_raise(cls, code): + if code < 0: + raise cls(code) + return code
+ + @classmethod +
[docs] def wrap_to_check_code_or_raise(cls, func): + @wraps(func) + def wrapper(*args, **kwargs): + return cls.check_code_or_raise(func(*args, **kwargs)) + + return wrapper
+ + @classmethod +
[docs] def try_or_raise(cls, arg, message=None): + if isinstance(arg, int): + return cls.check_code_or_raise(arg) + elif callable(arg): + return cls.wrap_to_check_code_or_raise(arg) + else: + raise TypeError("Expected 'int' or 'callable' but %s found" % type(arg))
+ + def __init__(self, code, message=None): + if message is None: + message = self.get_error_message_by_code(code) + + super().__init__(message) + + self._code = code + self._message = message + + def __str__(self): + return self._message + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._code, self._message + ) + + @property +
[docs] def code(self): + return self._code
+ + +
[docs]class KiwoomOpenApiWBooleanReturnCodeError(KiwoomOpenApiWError): + +
[docs] OP_ERR_SUCCESS = 1
+
[docs] OP_ERR_FAILURE = 0
+ + @classmethod +
[docs] def check_code_or_raise(cls, code, message=None): + if not code: + raise cls(message) + return code
+ + @classmethod +
[docs] def wrap_to_check_code_or_raise(cls, func, message=None): + @wraps(func) + def wrapper(*args, **kwargs): + return cls.check_code_or_raise(func(*args, **kwargs), message) + + return wrapper
+ + @classmethod +
[docs] def try_or_raise(cls, arg, message=None): + if isinstance(arg, (int, bool)): + return cls.check_code_or_raise(arg, message) + elif callable(arg): + return cls.wrap_to_check_code_or_raise(arg, message) + else: + raise TypeError( + "Expected 'int', 'bool' or 'callable' but %s found" % type(arg) + )
+ + def __init__(self, code, message=None): + super().__init__(message) + + self._code = code + self._message = message + + def __str__(self): + if self._message: + return self._message + else: + return self.__repr__() + + def __repr__(self): + return "{}({!r}, {!r})".format( + self.__class__.__name__, self._code, self._message + ) + + @property +
[docs] def code(self): + return self._code
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.html new file mode 100644 index 00000000..08eaee56 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.html @@ -0,0 +1,246 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler

+from contextlib import ExitStack
+from threading import RLock
+
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import (
+    QueueBasedIterableObserver,
+)
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions import (
+    KiwoomOpenApiWEventHandlerFunctions,
+)
+from koapy.utils.notimplemented import isimplemented
+
+
+
[docs]class KiwoomOpenApiWEventHandler(KiwoomOpenApiWEventHandlerFunctions): + def __init__(self, control): + self._control = control + self._observer = QueueBasedIterableObserver() + self._enter_count = 0 + self._should_exit = False + self._stack = ExitStack() + self._lock = RLock() + + @property +
[docs] def control(self): + return self._control
+ + @property +
[docs] def observer(self): + return self._observer
+ + @classmethod +
[docs] def names(cls): + names = [ + name + for name in dir(KiwoomOpenApiWEventHandlerFunctions) + if name.startswith("On") + ] + return names
+ +
[docs] def slots(self): + names = self.names() + slots = [getattr(self, name) for name in names] + names_and_slots_implemented = [ + (name, slot) for name, slot in zip(names, slots) if isimplemented(slot) + ] + return names_and_slots_implemented
+ +
[docs] def connect(self): + for name, slot in self.slots(): + getattr(self.control, name).connect(slot)
+ +
[docs] def disconnect(self): + for name, slot in self.slots(): + getattr(self.control, name).disconnect(slot)
+ +
[docs] def on_enter(self): + pass
+ +
[docs] def on_exit(self, exc_type=None, exc_value=None, traceback=None): + pass
+ +
[docs] def add_callback(self, callback, *args, **kwargs): + self._stack.callback(callback, *args, **kwargs)
+ +
[docs] def enter(self): + with self._lock: + self.connect() + self.on_enter() + self._should_exit = True
+ +
[docs] def exit(self, exc_type=None, exc_value=None, traceback=None): + with self._lock: + if self._should_exit: + self.disconnect() + self.on_exit(exc_type, exc_value, traceback) + self._stack.__exit__(exc_type, exc_value, traceback) + self._should_exit = False
+ +
[docs] def stop(self): + return self.observer.stop()
+ +
[docs] def close(self): + self.exit() + self.stop()
+ + def __enter__(self): + with self._lock: + if self._enter_count == 0: + self.enter() + self._enter_count += 1 + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is not None: + return self.exit(exc_type, exc_value, traceback) + with self._lock: + if self._enter_count > 0: + self._enter_count -= 1 + if self._enter_count == 0: + return self.exit(exc_type, exc_value, traceback) + return + + def __iter__(self): + with self: + return iter(self.observer)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.html new file mode 100644 index 00000000..4b50c135 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.html @@ -0,0 +1,165 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions

+from koapy.utils.notimplemented import notimplemented
+
+
+
[docs]class KiwoomOpenApiWEventHandlerFunctions: + @notimplemented +
[docs] def OnEventConnect(self, errcode): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + raise NotImplementedError
+ + @notimplemented +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + raise NotImplementedError
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.html new file mode 100644 index 00000000..3f27793a --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.html @@ -0,0 +1,170 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler

+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler import (
+    KiwoomOpenApiWEventHandler,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiWLoggingEventHandler(KiwoomOpenApiWEventHandler, Logging): +
[docs] def OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext): + self.logger.debug( + "OnReceiveTrData(%r, %r, %r, %r, %r)", + scrnno, + rqname, + trcode, + recordname, + prevnext, + )
+ +
[docs] def OnReceiveRealData(self, code, realtype, realdata): + self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata)
+ +
[docs] def OnReceiveMsg(self, scrnno, rqname, trcode, msg): + self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg)
+ +
[docs] def OnReceiveChejanData(self, gubun, itemcnt, fidlist): + self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist)
+ +
[docs] def OnEventConnect(self, errcode): + self.logger.debug("OnEventConnect(%r)", errcode)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.html new file mode 100644 index 00000000..035cb1ab --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.html @@ -0,0 +1,258 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget

+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable import (
+    KiwoomOpenApiWDynamicCallable,
+)
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler import (
+    KiwoomOpenApiWLoggingEventHandler,
+)
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin import (
+    KiwoomOpenApiWQAxWidgetMixin,
+)
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector import (
+    KiwoomOpenApiWSignalConnector,
+)
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import (
+    KiwoomOpenApiWDispatchSignature,
+    KiwoomOpenApiWEventHandlerSignature,
+)
+from koapy.compat.pyside2.QtAxContainer import QAxWidget
+from koapy.compat.pyside2.QtCore import QEvent, Qt
+from koapy.compat.pyside2.QtWidgets import QWidget
+from koapy.utils.logging.pyside2.QWidgetLogging import QWidgetLogging
+from koapy.utils.platform import is_32bit
+
+
+
[docs]class KiwoomOpenApiWQAxWidget(QWidgetLogging, KiwoomOpenApiWQAxWidgetMixin): + +
[docs] CLSID = "{D1ACAB7D-A3AF-49E4-9004-C9E98344E17A}"
+ +
[docs] METHOD_NAMES = KiwoomOpenApiWDispatchSignature.names()
+
[docs] EVENT_NAMES = KiwoomOpenApiWEventHandlerSignature.names()
+ + def __init__(self, *args, **kwargs): + # Check 32bit requirement + assert is_32bit(), "Control object should be created in 32bit environment" + + # Process arguments + control = None + parent = None + window_flags = None + + args = list(args) + kwargs = dict(kwargs) + + if len(args) > 0 and isinstance(args[0], str): + control = args.pop(0) + elif "c" in kwargs: + control = kwargs.pop("c") + + if len(args) > 0 and (args[0] is None or isinstance(args[0], QWidget)): + parent = args[0] + elif "parent" in kwargs: + parent = kwargs["parent"] + + if len(args) > 1: + window_flags = args[1] + elif "f" in kwargs: + window_flags = kwargs["f"] + + if control is None: + control = self.CLSID + + # Call super inits + QWidgetLogging.__init__(self, *args, **kwargs) + KiwoomOpenApiWQAxWidgetMixin.__init__(self) + + # Create QAxWidget + self._control = control + self._ax = QAxWidget(self._control, self) + + # Check if instantiation of the QAxWidget was successful + successful = not self._ax.isNull() + if not successful: + raise RuntimeError( + "Requested control {} could not be instantiated".format(self._control) + ) + + # Set methods as attributes + for method_name in self.METHOD_NAMES: + dynamic_callable = KiwoomOpenApiWDynamicCallable(self._ax, method_name) + setattr(self, method_name, dynamic_callable) + + # Set signals as attributes + for event_name in self.EVENT_NAMES: + signal_connector = KiwoomOpenApiWSignalConnector(event_name) + signal_connector.connect_to(self._ax) + setattr(self, event_name, signal_connector) + + # Enable logging for QAxWidget exceptions + self._ax.exception.connect(self._onException) # pylint: disable=no-member + + # Enable logging for OpenAPI events + self._event_logger = KiwoomOpenApiWLoggingEventHandler(self) + self._event_logger.connect() + + def _onException( + self, code, source, desc, help + ): # pylint: disable=redefined-builtin + self.logger.error("QAxBaseException(%r, %r, %r, %r)", code, source, desc, help) + + def __getattr__(self, name): + try: + return getattr(self._ax, name) + except AttributeError as e: + raise AttributeError( + "'{}' object has no attribute '{}'".format( + self.__class__.__name__, name + ) + ) from e + +
[docs] def changeEvent(self, event): + if event.type() == QEvent.WindowStateChange: + if self.windowState() & Qt.WindowMinimized: + event.accept()
+ +
[docs] def closeEvent(self, event): + self.hide() + event.ignore()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.html new file mode 100644 index 00000000..08f9dbe0 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.html @@ -0,0 +1,145 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin

+
[docs]class KiwoomOpenApiWQAxWidgetMixin: + + pass
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.html new file mode 100644 index 00000000..b9bc5733 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.html @@ -0,0 +1,208 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector

+import inspect
+import threading
+
+from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import (
+    KiwoomOpenApiWEventHandlerSignature,
+)
+from koapy.compat.pyside2 import PYQT5, PYSIDE2, PythonQtError
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiWSignalConnector(Logging): + def __init__(self, name=None): + super().__init__() + + self._name = name + self._lock = threading.RLock() + self._slots = list() + + self._signature = KiwoomOpenApiWEventHandlerSignature.from_name(self._name) + self._param_types = [ + (p.annotation) for p in self._signature.parameters.values() + ] + self._signal = self._signature.to_pyside2_event_signal() + +
[docs] def is_valid_slot(self, slot): + slot_signature = inspect.signature(slot) + slot_types = [(p.annotation) for p in slot_signature.parameters.values()] + condition = len(self._param_types) == len( + slot_types + ) # currently only check parameter length + return condition
+ +
[docs] def connect_to(self, control): + if PYSIDE2: + return control.connect(self._signal, self) + elif PYQT5: + return getattr(control, self._name).connect(self) + else: + raise PythonQtError("Unsupported Qt bindings")
+ +
[docs] def connect(self, slot): + if not self.is_valid_slot(slot): + raise TypeError("Invalid slot: %s" % slot) + with self._lock: + if slot not in self._slots: + self._slots.append(slot)
+ +
[docs] def disconnect(self, slot=None): + with self._lock: + if slot is None: + self._slots.clear() + elif slot in self._slots: + self._slots.remove(slot) + else: + self.logger.warning("Tried to disconnect a slot that doesn't exist")
+ +
[docs] def call(self, *args, **kwargs): + # make a copy in order to prevent modification during iteration problem + with self._lock: + slots = list(self._slots) + # TODO: use Thread with await/join for concurrency? + for slot in slots: + slot(*args, **kwargs)
+ + def __call__(self, *args, **kwargs): + return self.call(*args, **kwargs)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.html b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.html new file mode 100644 index 00000000..ba220208 --- /dev/null +++ b/_modules/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.html @@ -0,0 +1,327 @@ + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature

+from collections import OrderedDict
+from inspect import Parameter, Signature
+
+import pythoncom
+
+from win32com.client import genpy, selecttlb
+
+from koapy.compat.pyside2.QtCore import SIGNAL
+
+
+
[docs]def BuildOleItems(clsid): + tlbs = selecttlb.EnumTlbs() + tlbs = {tlb.clsid: tlb for tlb in tlbs} + + tlbSpec = tlbs.get(clsid) + + if tlbSpec is None: + return {} # raise LookupError('KHOpenAPI Module not found') + + if tlbSpec.dll is None: + tlb = pythoncom.LoadRegTypeLib( + tlbSpec.clsid, int(tlbSpec.major, 16), int(tlbSpec.minor, 16), tlbSpec.lcid + ) + else: + tlb = pythoncom.LoadTypeLib(tlbSpec.dll) + + gen = genpy.Generator(tlb, tlbSpec.dll, None, bBuildHidden=1) + oleItems, _enumItems, _recordItems, _vtableItems = gen.BuildOleItemsFromType() + + oleItems = {str(clsId): oleItem for clsId, oleItem in oleItems.items()} + + return oleItems
+ + +
[docs]class KiwoomOpenApiWSignature(Signature): + +
[docs] MODULE_CLSID = "{1F8A15ED-A979-488F-9694-1EDA98188FFC}"
+ +
[docs] OLE_ITEMS = BuildOleItems(MODULE_CLSID)
+ +
[docs] DISPATCH_CLSID = "{85B07632-4F84-4CEF-991D-C79DE781363D}"
+
[docs] EVENT_CLSID = "{952B31F8-06FD-4D5A-A021-5FF57F5030AE}"
+ +
[docs] PYTHONTYPE_TO_QTTYPE = { + int: "int", + str: "const QString&", + }
+ +
[docs] COMTYPE_TO_PYTHONTYPE = { + pythoncom.VT_I4: int, + pythoncom.VT_BSTR: str, + pythoncom.VT_VARIANT: type( + None + ), # QVariant does not exist in PySide2 (Currently PyQt5 only) + pythoncom.VT_VOID: type(None), + }
+ + def __init__( + self, name, parameters=None, return_annotation=Signature.empty, entry=None + ): + self._name = name + self._entry = entry + super().__init__(parameters, return_annotation=return_annotation) + + @property +
[docs] def name(self): + return self._name
+ + @classmethod + def _pythontype_to_qttype(cls, typ): + return cls.PYTHONTYPE_TO_QTTYPE[typ] + +
[docs] def to_pyside2_function_prototype(self): + name = self._name + parameters = self.parameters + parameters = parameters.values() + parameters = [self._pythontype_to_qttype(p.annotation) for p in parameters] + prototype = "{}({})".format(name, ", ".join(parameters)) + return prototype
+ +
[docs] def to_pyside2_event_signal(self): + return SIGNAL(self.to_pyside2_function_prototype())
+ + @classmethod + def _comtype_to_pythontype(cls, typ): + return cls.COMTYPE_TO_PYTHONTYPE[typ] + + @classmethod + def _from_entry(cls, name, entry): + arg_names = entry.names[1:] + arg_types = [typ[0] for typ in entry.desc[2]] + return_type = entry.desc[8][0] + parameters = [ + Parameter( + name=arg_name, + kind=Parameter.POSITIONAL_OR_KEYWORD, + annotation=cls._comtype_to_pythontype(arg_type), + ) + for arg_name, arg_type in zip(arg_names, arg_types) + ] + return_annotation = cls._comtype_to_pythontype(return_type) + signature = cls( + name=name, + parameters=parameters, + return_annotation=return_annotation, + entry=entry, + ) + return signature
+ + +
[docs]class KiwoomOpenApiWDispatchSignature(KiwoomOpenApiWSignature): + +
[docs] DISPATCH_SIGNATURES_BY_NAME = {}
+ + @classmethod +
[docs] def from_name(cls, name): + return cls.DISPATCH_SIGNATURES_BY_NAME[name]
+ + @classmethod +
[docs] def names(cls): + return list(cls.DISPATCH_SIGNATURES_BY_NAME.keys())
+ + +
[docs]def LoadDispatchSignatures(oleItems, clsId): + if clsId not in oleItems: + return {} + dispatch = oleItems[clsId] + dispatch_funcs = [ + (name, entry) + for name, entry in dispatch.mapFuncs.items() + if not any( + [ + entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED + and entry.desc[0] != pythoncom.DISPID_NEWENUM, + entry.desc[3] != pythoncom.FUNC_DISPATCH, + entry.desc[0] == pythoncom.DISPID_NEWENUM, + ] + ) + ] + dispatch_signatures_by_name = OrderedDict() + for func_name, entry in dispatch_funcs: + signature = KiwoomOpenApiWDispatchSignature._from_entry( + func_name, entry + ) # pylint: disable=protected-access + dispatch_signatures_by_name[func_name] = signature + return dispatch_signatures_by_name
+ + +
[docs]KiwoomOpenApiWDispatchSignature.DISPATCH_SIGNATURES_BY_NAME = LoadDispatchSignatures( + KiwoomOpenApiWSignature.OLE_ITEMS, KiwoomOpenApiWSignature.DISPATCH_CLSID +)
+ + +
[docs]class KiwoomOpenApiWEventHandlerSignature(KiwoomOpenApiWSignature): + +
[docs] EVENT_HANDLER_SIGNATURES_BY_NAME = {}
+ + @classmethod +
[docs] def from_name(cls, name): + return cls.EVENT_HANDLER_SIGNATURES_BY_NAME[name]
+ + @classmethod +
[docs] def names(cls): + return list(cls.EVENT_HANDLER_SIGNATURES_BY_NAME.keys())
+ + +
[docs]def LoadEventHandlerSignatures(oleItems, clsId): + if clsId not in oleItems: + return {} + event = oleItems[clsId] + event_funcs = event.mapFuncs.items() + event_handler_signatures_by_name = OrderedDict() + for func_name, entry in event_funcs: + signature = KiwoomOpenApiWEventHandlerSignature._from_entry( + func_name, entry + ) # pylint: disable=protected-access + event_handler_signatures_by_name[func_name] = signature + return event_handler_signatures_by_name
+ + +
[docs]KiwoomOpenApiWEventHandlerSignature.EVENT_HANDLER_SIGNATURES_BY_NAME = ( + LoadEventHandlerSignatures( + KiwoomOpenApiWSignature.OLE_ITEMS, KiwoomOpenApiWSignature.EVENT_CLSID + ) +)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KiwoomOpenApiPlusBroker.html b/_modules/koapy/backtrader/KiwoomOpenApiPlusBroker.html new file mode 100644 index 00000000..1747d90e --- /dev/null +++ b/_modules/koapy/backtrader/KiwoomOpenApiPlusBroker.html @@ -0,0 +1,578 @@ + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusBroker — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KiwoomOpenApiPlusBroker

+import collections
+
+from backtrader import BrokerBase, BuyOrder, Order, SellOrder
+from backtrader.comminfo import CommInfoBase
+from backtrader.position import Position
+from backtrader.utils.py3 import with_metaclass
+
+from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore
+
+
+
[docs]class KiwoomOpenApiPlusCommInfo(CommInfoBase): + + # pylint: disable=no-member + +
[docs] params = ( + ("stocklike", True), + ("commtype", CommInfoBase.COMM_PERC), + ("percabs", False), + ("commission", 0.015), + ("tax", 0.25), + ("mult", 1.0), + )
+ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if self._commtype == self.COMM_PERC and not self.p.percabs: + self.p.tax /= 100.0 + + def _getcommissionbuy(self, size, price, pseudoexec): + return size * price * self.p.commission * self.p.mult + + def _getcommissionsell(self, size, price, pseudoexec): + return abs(size) * price * (self.p.commission + self.p.tax) * self.p.mult + + def _getcommission(self, size, price, pseudoexec): + if size < 0: + return self._getcommissionsell(size, price, pseudoexec) + else: + return self._getcommissionbuy(size, price, pseudoexec)
+ + +
[docs]class MetaKiwoomOpenApiPlusBroker(BrokerBase.__class__): + def __init__(cls, name, bases, dct): + super().__init__(name, bases, dct) + KiwoomOpenApiPlusStore.BrokerCls = cls
+ + +
[docs]class KiwoomOpenApiPlusBroker(with_metaclass(MetaKiwoomOpenApiPlusBroker, BrokerBase)): + +
[docs] params = ( + ("use_positions", True), + ("commission", KiwoomOpenApiPlusCommInfo()), + )
+ + _store = KiwoomOpenApiPlusStore + + def __init__(self, *args, **kwargs): + super().__init__() + + self.k = self._store(*args, **kwargs) + + self.orders = collections.OrderedDict() # orders by order id + self.notifs = collections.deque() # holds orders which are notified + + self.opending = collections.defaultdict(list) # pending transmission + self.brackets = dict() # confirmed brackets + + self.startingcash = self.cash = 0.0 + self.startingvalue = self.value = 0.0 + self.positions = collections.defaultdict(Position) + +
[docs] def start(self): + super().start() + self.k.start(broker=self) + self.startingcash = self.cash = self.k.get_cash() + self.startingvalue = self.value = self.k.get_value() + + if self.p.use_positions: # pylint: disable=no-member + for p in self.k.get_positions(): + is_sell = p["side"] == "sell" + size = p["units"] + if is_sell: + size = -size + price = p["avgPrice"] + self.positions[p["instrument"]] = Position(size, price)
+ +
[docs] def data_started(self, data): + pos = self.getposition(data) + + if pos.size < 0: + # pylint: disable=unexpected-keyword-arg + order = SellOrder( + data=data, + size=pos.size, + price=pos.price, + exectype=Order.Market, + simulated=True, + ) + + order.addcomminfo(self.getcommissioninfo(data)) + order.execute( + 0, + pos.size, + pos.price, + 0, + 0.0, + 0.0, + pos.size, + 0.0, + 0.0, + 0.0, + 0.0, + pos.size, + pos.price, + ) + + order.completed() + self.notify(order) + + elif pos.size > 0: + # pylint: disable=unexpected-keyword-arg + order = BuyOrder( + data=data, + size=pos.size, + price=pos.price, + exectype=Order.Market, + simulated=True, + ) + + order.addcomminfo(self.getcommissioninfo(data)) + order.execute( + 0, + pos.size, + pos.price, + 0, + 0.0, + 0.0, + pos.size, + 0.0, + 0.0, + 0.0, + 0.0, + pos.size, + pos.price, + ) + + order.completed() + self.notify(order)
+ +
[docs] def stop(self): + super().stop() + self.k.stop()
+ +
[docs] def getcash(self): + self.cash = self.k.get_cash() + return self.cash
+ +
[docs] def getvalue(self, datas=None): + self.value = self.k.get_value() + return self.value
+ +
[docs] def getposition(self, data, clone=True): # pylint: disable=arguments-differ + pos = self.positions[data._dataname] # pylint: disable=protected-access + if clone: + pos = pos.clone() + return pos
+ +
[docs] def orderstatus(self, order): + order = self.orders[order.ref] + return order.status
+ + def _submit(self, oref): + order = self.orders[oref] + order.submit(self) + self.notify(order) + for o in self._bracketnotif(order): + o.submit(self) + self.notify(o) + + def _reject(self, oref): + order = self.orders[oref] + order.reject(self) + self.notify(order) + self._bracketize(order, cancel=True) + + def _accept(self, oref): + order = self.orders[oref] + order.accept() + self.notify(order) + for o in self._bracketnotif(order): + o.accept(self) + self.notify(o) + + def _cancel(self, oref): + order = self.orders[oref] + order.cancel() + self.notify(order) + self._bracketize(order, cancel=True) + + def _expire(self, oref): + order = self.orders[oref] + order.expire() + self.notify(order) + self._bracketize(order, cancel=True) + + def _bracketnotif(self, order): + pref = getattr(order.parent, "ref", order.ref) # parent ref or self + br = self.brackets.get(pref, None) # to avoid recursion + return br[-2:] if br is not None else [] + + def _bracketize(self, order, cancel=False): + pref = getattr(order.parent, "ref", order.ref) # parent ref or self + br = self.brackets.pop(pref, None) # to avoid recursion + if br is None: + return + + if not cancel: + if len(br) == 3: # all 3 orders in place, parent was filled + br = br[1:] # discard index 0, parent + for o in br: + o.activate() # simulate activate for children + self.brackets[pref] = br # not done - reinsert children + + elif len(br) == 2: # filling a children + oidx = br.index(order) # find index to filled (0 or 1) + self._cancel(br[1 - oidx].ref) # cancel remaining (1 - 0 -> 1) + else: + # Any cancellation cancel the others + for o in br: + if o.alive(): + self._cancel(o.ref) + + def _fill(self, oref, size, price, ttype, **kwargs): + order = self.orders[oref] + + if not order.alive(): # can be a bracket + pref = getattr(order.parent, "ref", order.ref) + if pref not in self.brackets: + msg = ( + "Order fill received for {}, with price {} and size {} " + "but order is no longer alive and is not a bracket. " + "Unknown situation" + ) + msg.format(order.ref, price, size) + self.put_notification( + msg, order, price, size + ) # pylint: disable=no-member + return + + # [main, stopside, takeside], neg idx to array are -3, -2, -1 + if ttype == "STOP_LOSS_FILLED": + order = self.brackets[pref][-2] + elif ttype == "TAKE_PROFIT_FILLED": + order = self.brackets[pref][-1] + else: + msg = ( + "Order fill received for {}, with price {} and size {} " + "but order is no longer alive and is a bracket. " + "Unknown situation" + ) + msg.format(order.ref, price, size) + self.put_notification( + msg, order, price, size + ) # pylint: disable=no-member + return + + data = order.data + pos = self.getposition(data, clone=False) + psize, pprice, opened, closed = pos.update(size, price) + + comminfo = self.getcommissioninfo(data) # pylint: disable=unused-variable + + closedvalue = closedcomm = 0.0 + openedvalue = openedcomm = 0.0 + margin = pnl = 0.0 + + if size >= 0: + openedvalue = comminfo.getvaluesize(size, price) + openedcomm = comminfo.confirmexec(size, price) + else: + closedvalue = comminfo.getvaluesize(size, price) + closedcomm = comminfo.confirmexec(size, price) + + order.execute( + data.datetime[0], + size, + price, + closed, + closedvalue, + closedcomm, + opened, + openedvalue, + openedcomm, + margin, + pnl, + psize, + pprice, + ) + + if order.executed.remsize: + order.partial() + self.notify(order) + else: + order.completed() + self.notify(order) + self._bracketize(order) + + def _transmit(self, order): + oref = order.ref + pref = getattr(order.parent, "ref", oref) # parent ref or self + + if order.transmit: + if oref != pref: # children order + # Put parent in orders dict, but add stopside and takeside + # to order creation. Return the takeside order, to have 3s + takeside = order # alias for clarity + parent, stopside = self.opending.pop(pref) + for o in parent, stopside, takeside: + self.orders[o.ref] = o # write them down + + self.brackets[pref] = [parent, stopside, takeside] + self.k.order_create(parent, stopside, takeside) + return takeside # parent was already returned + + else: # Parent order, which is not being transmitted + self.orders[order.ref] = order + return self.k.order_create(order) + + # Not transmitting + self.opending[pref].append(order) + return order + +
[docs] def buy( + self, + owner, + data, + size, + price=None, + plimit=None, + exectype=None, + valid=None, + tradeid=0, + oco=None, + trailamount=None, + trailpercent=None, + parent=None, + transmit=True, + **kwargs + ): # pylint: disable=arguments-differ + + # pylint: disable=unexpected-keyword-arg + order = BuyOrder( + owner=owner, + data=data, + size=size, + price=price, + pricelimit=plimit, + exectype=exectype, + valid=valid, + tradeid=tradeid, + trailamount=trailamount, + trailpercent=trailpercent, + parent=parent, + transmit=transmit, + ) + + order.addinfo(**kwargs) + order.addcomminfo(self.getcommissioninfo(data)) + return self._transmit(order)
+ +
[docs] def sell( + self, + owner, + data, + size, + price=None, + plimit=None, + exectype=None, + valid=None, + tradeid=0, + oco=None, + trailamount=None, + trailpercent=None, + parent=None, + transmit=True, + **kwargs + ): # pylint: disable=arguments-differ + + # pylint: disable=unexpected-keyword-arg + order = SellOrder( + owner=owner, + data=data, + size=size, + price=price, + pricelimit=plimit, + exectype=exectype, + valid=valid, + tradeid=tradeid, + trailamount=trailamount, + trailpercent=trailpercent, + parent=parent, + transmit=transmit, + ) + + order.addinfo(**kwargs) + order.addcomminfo(self.getcommissioninfo(data)) + return self._transmit(order)
+ +
[docs] def cancel(self, order): + order = self.orders[order.ref] + if order.status == Order.Cancelled: + return + return self.k.order_cancel(order)
+ +
[docs] def notify(self, order): + self.notifs.append(order.clone())
+ +
[docs] def get_notification(self): + if not self.notifs: + return None + return self.notifs.popleft()
+ +
[docs] def next(self): + self.notifs.append(None)
+ + # below may not accurate + +
[docs] def submit(self, order): + return self._transmit(order)
+ +
[docs] def add_order_history(self, orders, notify=False): + return self.k.add_order_history(orders, notify)
+ +
[docs] def set_fund_history(self, fund): + return self.k.set_fund_history(fund)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KiwoomOpenApiPlusData.html b/_modules/koapy/backtrader/KiwoomOpenApiPlusData.html new file mode 100644 index 00000000..2ac6c902 --- /dev/null +++ b/_modules/koapy/backtrader/KiwoomOpenApiPlusData.html @@ -0,0 +1,507 @@ + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KiwoomOpenApiPlusData

+import datetime
+
+from backtrader import date2num, num2date
+from backtrader.feed import DataBase
+from backtrader.utils.py3 import queue
+from pytz import utc
+
+from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class MetaKiwoomOpenApiPlusData(type(Logging), type(DataBase)): + def __init__(cls, clsname, bases, dct): + super().__init__(clsname, bases, dct) + KiwoomOpenApiPlusStore.DataCls = cls
+ + +
[docs]class KiwoomOpenApiPlusData(DataBase, Logging, metaclass=MetaKiwoomOpenApiPlusData): + + # pylint: disable=no-member + +
[docs] params = ( + ("qcheck", 0.5), + ("historical", False), # do backfilling at the start + ("backfill_start", True), # do backfilling at the start + ("backfill", True), # do backfilling when reconnecting + ("backfill_from", None), # additional data source to do backfill from + ("useask", False), + ("reconnect", True), + ("reconnections", -1), # forever + ("reconntimeout", 5.0), + ("tz", "Asia/Seoul"), + ( + "tzinput", + None, + ), # this should be none (utc) since we are already putting datetimes converted to utc + ("calendar", None), + )
+ + _store = KiwoomOpenApiPlusStore + + _ST_FROM, _ST_START, _ST_LIVE, _ST_HISTORBACK, _ST_OVER = range(5) + + def __init__(self, *args, **kwargs): + self.k = self._store(*args, **kwargs) + + if self.p.dataname not in self.k.datanames: + self.k.datanames.append(self.p.dataname) + + self.qlive = queue.Queue() + self.qhist = queue.Queue() + + self.contractdetails = None + + self._statelivereconn = False + self._storedmsg = dict() + self._state = self._ST_OVER + self._reconns = 0 + + self._tz = self._gettz() + + def _timeoffset(self): + return self.k.timeoffset() + +
[docs] def isnaive(self, dt): + return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None
+ +
[docs] def asutc(self, dt, tz=None, naive=True): + if tz is None: + tz = self._tz + if self.isnaive(dt) and tz is not None: + dt = tz.localize(dt) + dt = dt.astimezone(utc) + if naive: + dt = dt.replace(tzinfo=None) + return dt
+ +
[docs] def date2num(self, dt, tz=None): # pylint: disable=arguments-differ + dt = self.asutc(dt, tz) + return date2num(dt)
+ +
[docs] def num2date(self, dt=None, tz=None, naive=False): + if dt is None: + dt = self.lines.datetime[0] + if tz is None: + tz = self._tz + return num2date(dt, tz, naive)
+ +
[docs] def fromtimestamp(self, timestamp, tz=None): + if tz is None: + tz = self._tz + return datetime.datetime.fromtimestamp(timestamp, tz=tz)
+ +
[docs] def islive(self): + return not self.p.historical
+ +
[docs] def setenvironment(self, env): + super().setenvironment(env) + env.addstore(self.k)
+ +
[docs] def start(self): + super().start() + + self.qlive = queue.Queue() + self.qhist = queue.Queue() + + self._statelivereconn = False + self._storedmsg = dict() + self._state = self._ST_OVER + + self.k.start(data=self) + + otf = self.k.get_granularity(self.p.timeframe, self.p.compression) + + if otf is None: + self.logger.warning( + "Given timeframe and compression not supported: (%s, %s)", + self.p.timeframe, + self.p.compression, + ) + self.put_notification(self.NOTSUPPORTED_TF) + self._state = self._ST_OVER + return + + self.contractdetails = cd = self.k.get_instrument(self.p.dataname) + + if cd is None: + self.logger.warning("Given dataname is not supported") + self.put_notification(self.NOTSUBSCRIBED) + self._state = self._ST_OVER + return + + if self.p.backfill_from is not None: + self._state = self._ST_FROM + self.p.backfill_from.setenvironment(self._env) + self.p.backfill_from._start() # pylint: disable=protected-access + else: + self._start_finish() + self._state = self._ST_START + self._st_start() + + self._reconns = 0
+ + def _st_start(self, instart=True, tmout=None): + if self.p.historical: + self.put_notification(self.DELAYED) + + dtend = None + if self.todate < float("inf"): + dtend = self.num2date(self.todate) + + dtbegin = None + if self.fromdate > float("-inf"): + dtbegin = self.num2date(self.fromdate) + + self.qhist = self.k.candles( + self.p.dataname, dtbegin, dtend, self.p.timeframe, self.p.compression + ) + + self._state = self._ST_HISTORBACK + + return True + else: + self.qlive = self.k.streaming_prices(self.p.dataname, tmout=tmout) + + if instart: + self._statelivereconn = self.p.backfill_start + else: + self._statelivereconn = self.p.backfill + + if self._statelivereconn: + self.put_notification(self.DELAYED) + + self._state = self._ST_LIVE + + if instart: + self._reconns = self.p.reconnections + + if instart and not self.p.backfill_start: + self.put_notification(self.DELAYED) + + msg = self.k.initial_today_historical_msg(data=self) + + self.qhist.put(msg) + self.qhist.put({}) + + self._state = self._ST_HISTORBACK + + return True + +
[docs] def stop(self): + super().stop() + self.k.stop()
+ +
[docs] def haslivedata(self): + return bool(self._storedmsg or not self.qlive.empty())
+ + def _load(self): + if self._state == self._ST_OVER: + return False + + while True: + if self._state == self._ST_LIVE: + try: + msg = self._storedmsg.pop(None, None) or self.qlive.get( + timeout=self._qcheck + ) + except queue.Empty: + return None + + if msg is None: + self.put_notification(self.CONNBROKEN) + + if not self.p.reconnect or self._reconns == 0: + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + self._reconns -= 1 + self._st_start(instart=False, tmout=self.p.reconntimeout) + continue + + if "code" in msg: + self.put_notification(self.CONNBROKEN) + + code = msg["code"] + + if code not in [599, 598, 596]: + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + if not self.p.reconnect or self._reconns == 0: + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + self._reconns -= 1 + self._st_start(instart=False, tmout=self.p.reconntimeout) + continue + + self._reconns = self.p.reconnections + + if not self._statelivereconn: + if self._laststatus != self.LIVE: + if self.qlive.qsize() <= 1: + self.put_notification(self.LIVE) + + ret = self._load_tick(msg) + if ret: + return True + continue + + self._storedmsg[None] = msg + + if self._laststatus != self.DELAYED: + self.put_notification(self.DELAYED) + + dtend = None + if len(self) > 1: + dtbegin = self.datetime.datetime(-1) + elif self.fromdate > float("-inf"): + dtbegin = self.num2date(self.fromdate) + else: + dtbegin = None + + dtend = self.fromtimestamp(int(msg["time"]) / 10**6) + + self.qhist = self.k.candles( + self.p.dataname, + dtbegin, + dtend, + self.p.timeframe, + self.p.compression, + ) + + self._state = self._ST_HISTORBACK + self._statelivereconn = False + continue + + elif self._state == self._ST_HISTORBACK: + msg = self.qhist.get() + if msg is None: + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + elif "code" in msg: + self.put_notification(self.NOTSUBSCRIBED) + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + if msg: + if self._load_history(msg): + return True + continue + else: + if self.p.historical: + self.put_notification(self.DISCONNECTED) + self._state = self._ST_OVER + return False + + self._state = self._ST_LIVE + continue + + elif self._state == self._ST_FROM: + if not self.p.backfill_from.next(): + self._state = self._ST_START + continue + + # copy lines of the same name + for alias in self.lines.getlinealiases(): + lsrc = getattr(self.p.backfill_from.lines, alias) + ldst = getattr(self.lines, alias) + + ldst[0] = lsrc[0] + + return True + + elif self._state == self._ST_START: + if not self._st_start(instart=False): + self._state = self._ST_OVER + return False + + def _load_tick(self, msg): + dtobj = self.fromtimestamp(int(msg["time"]) / 10**6) + dt = self.date2num(dtobj) + if dt <= self.lines.datetime[-1]: + return False # time already seen + + # Common fields + self.lines.datetime[0] = dt + self.lines.volume[0] = 0.0 + self.lines.openinterest[0] = 0.0 + + # Put the prices into the bar + tick = float(msg["ask"]) if self.p.useask else float(msg["bid"]) + self.lines.open[0] = tick + self.lines.high[0] = tick + self.lines.low[0] = tick + self.lines.close[0] = tick + self.lines.volume[0] = 0.0 + self.lines.openinterest[0] = 0.0 + + return True + + def _load_history(self, msg): + dtobj = self.fromtimestamp(int(msg["time"]) / 10**6) + dt = self.date2num(dtobj) + if dt <= self.lines.datetime[-1]: + return False # time already seen + + # Common fields + self.lines.datetime[0] = dt + self.lines.volume[0] = float(msg["volume"]) + self.lines.openinterest[0] = 0.0 + + # Put the prices into the bar + self.lines.open[0] = float(msg["open"]) + self.lines.high[0] = float(msg["high"]) + self.lines.low[0] = float(msg["low"]) + self.lines.close[0] = float(msg["close"]) + + return True
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.html b/_modules/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.html new file mode 100644 index 00000000..e2a246a9 --- /dev/null +++ b/_modules/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.html @@ -0,0 +1,464 @@ + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusEventStreamer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KiwoomOpenApiPlusEventStreamer

+import datetime
+import threading
+
+import rx
+
+from exchange_calendars import get_calendar
+from rx import operators as ops
+from rx.core.typing import Observer
+from rx.scheduler import ThreadPoolScheduler
+from rx.subject import Subject
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import (
+    KiwoomOpenApiPlusRealType,
+)
+from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator import (
+    QueueBasedBufferedIterator,
+)
+from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import (
+    QueueBasedIterableObserver,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusPriceEventChannel(Logging): + + _krx_timezone = get_calendar("XKRX").tz + + def __init__(self, stub): + self._stub = stub + self._fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") + + self._request_observer = QueueBasedIterableObserver() + self._request_iterator = iter(self._request_observer) + self._response_iterator = self._stub.BidirectionalRealCall( + self._request_iterator + ) + self._response_subject = Subject() + self._response_scheduler_max_workers = 8 + self._response_scheduler = ThreadPoolScheduler( + self._response_scheduler_max_workers + ) + self._buffered_response_iterator = QueueBasedBufferedIterator( + self._response_iterator + ) + self._response_observable = rx.from_iterable( + self._buffered_response_iterator, self._response_scheduler + ) + self._response_subscription = self._response_observable.subscribe( + self._response_subject + ) + + self._subjects_by_code = {} + + self.initialize() + +
[docs] def close(self): + for _code, (_subject, subscription) in self._subjects_by_code.items(): + subscription.dispose() + self._response_subscription.dispose() + self._buffered_response_iterator.stop() + self._response_iterator.cancel()
+ + def __del__(self): + self.close() + +
[docs] def initialize(self): + request = KiwoomOpenApiPlusService_pb2.BidirectionalRealRequest() + request.initialize_request.fid_list.extend( + self._fid_list + ) # pylint: disable=no-member + self._request_observer.on_next(request)
+ +
[docs] def register_code(self, code): + request = KiwoomOpenApiPlusService_pb2.BidirectionalRealRequest() + code_list = [code] + fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") + request.register_request.code_list.extend( + code_list + ) # pylint: disable=no-member + request.register_request.fid_list.extend(fid_list) # pylint: disable=no-member + self._request_observer.on_next(request) + self.logger.debug("Registering code %s for real events", code)
+ +
[docs] def is_for_code(self, response, code): + return response.arguments[0].string_value == code
+ +
[docs] def filter_for_code(self, code): + return ops.filter(lambda response: self.is_for_code(response, code))
+ +
[docs] def is_valid_price_event(self, response): + return all(name in response.single_data.names for name in ["20", "27", "28"])
+ +
[docs] def filter_price_event(self): + return ops.filter(self.is_valid_price_event)
+ +
[docs] def time_to_timestamp(self, fid20): + dt = datetime.datetime.now(self._krx_timezone).date() + tm = datetime.datetime.strptime(fid20, "%H%M%S").time() + dt = datetime.datetime.combine(dt, tm) + dt = self._krx_timezone.localize(dt) + return dt.timestamp() * (10**6)
+ +
[docs] def event_to_dict(self, response): + single_data = dict(zip(response.single_data.names, response.single_data.values)) + result = { + "time": self.time_to_timestamp(single_data["20"]), + "bid": abs(float(single_data["28"])), + "ask": abs(float(single_data["27"])), + } + return result
+ +
[docs] def convert_to_dict(self): + return ops.map(self.event_to_dict)
+ +
[docs] def get_observable_for_code(self, code): + self.register_code(code) + if code not in self._subjects_by_code: + subject = Subject() + subscription = self._response_subject.pipe( + self.filter_for_code(code), + self.filter_price_event(), + self.convert_to_dict(), + ).subscribe(subject) + self._subjects_by_code[code] = (subject, subscription) + subject, subscription = self._subjects_by_code[code] + return subject
+ + +
[docs]class KiwoomOpenApiPlusOrderEventChannel: + def __init__(self, stub): + self._stub = stub + + request = KiwoomOpenApiPlusService_pb2.ListenRequest() + self._response_iterator = self._stub.OrderListen(request) + self._response_subject = Subject() + self._response_scheduler_max_workers = 8 + self._response_scheduler = ThreadPoolScheduler( + self._response_scheduler_max_workers + ) + self._buffered_response_iterator = QueueBasedBufferedIterator( + self._response_iterator + ) + self._response_observable = rx.from_iterable( + self._buffered_response_iterator, self._response_scheduler + ) + self._response_subscription = self._response_observable.subscribe( + self._response_subject + ) + + self._observable = Subject() + self._subscription = self._response_subject.pipe( + self.filter_chejan_response(), + self.convert_to_dict(), + ).subscribe(self._observable) + +
[docs] def close(self): + self._subscription.dispose() + self._response_subscription.dispose() + self._buffered_response_iterator.stop() + self._response_iterator.cancel()
+ + def __del__(self): + self.close() + +
[docs] def is_chejan_response(self, response): + name = response.name + gubun = response.arguments[0].string_value + if name == "OnReceiveChejanData" and gubun == "0": + data = dict(zip(response.single_data.names, response.single_data.values)) + order_type = data["주문구분"] + hoga_type = data["매매구분"] + status = data["주문상태"] + market_order_created_and_filled = ( + order_type in ["+매수", "-매도"] + and hoga_type in ["시장가"] + and status in ["체결"] + ) + limit_order_created = ( + order_type in ["+매수", "-매도"] + and hoga_type in ["보통"] + and status in ["접수"] + and data["819"] in ["0"] + ) # 취소 확인 뒤에 오는 원주문 이벤트는 819 가 1 로 들어오는 것 같음 + order_filled = order_type in ["+매수", "-매도"] and status in ["체결"] + order_canceled = order_type in ["매수취소", "매도취소"] and status in ["확인"] + condition = any( + [ + market_order_created_and_filled, + limit_order_created, + order_filled, + order_canceled, + ] + ) + return condition + return False
+ +
[docs] def filter_chejan_response(self): + return ops.filter(self.is_chejan_response)
+ +
[docs] def event_to_dict(self, response): + result = {} + data = dict(zip(response.single_data.names, response.single_data.values)) + original_order_no = data["원주문번호"] + if int(original_order_no): + status = data["주문상태"] + if status == "확인": + reject_reason = data["거부사유"] + result = { + "type": "ORDER_CANCEL", + "orderId": original_order_no, + "reason": reject_reason if int(reject_reason) else "ORDER_FILLED", + } + else: + status = data["주문상태"] + hoga_type = data["매매구분"] + if status == "접수": + if hoga_type == "보통": + order_no = data["주문번호"] + result = { + "type": "LIMIT_ORDER_CREATE", + "id": order_no, + } + elif hoga_type == "시장가": + pass + else: + self.logger.warning("Unexpected hoga type %s", hoga_type) + elif status == "체결": + if hoga_type == "보통": + order_no = data["주문번호"] + units = data["단위체결량"] + buy_or_sell = data["주문구분"] + side = { + "+매수": "buy", + "-매도": "sell", + }[buy_or_sell] + price = data["단위체결가"] + result = { + "type": "ORDER_FILLED", + "orderId": order_no, + "units": int(units), + "side": side, + "price": abs(float(price)), + } + elif hoga_type == "시장가": + order_no = data["주문번호"] + units = data["단위체결량"] + buy_or_sell = data["주문구분"] + side = { + "+매수": "buy", + "-매도": "sell", + }[buy_or_sell] + price = data["단위체결가"] + result = { + "type": "MARKET_ORDER_CREATE", + "id": order_no, + "tradeOpened": {"id": order_no}, + "units": int(units), + "side": side, + "price": abs(float(price)), + } + else: + self.logger.warning("Unexpected hoga type %s", hoga_type) + else: + self.logger.warning("Unexcpected status %s", status) + return result
+ +
[docs] def convert_to_dict(self): + return ops.map(self.event_to_dict)
+ +
[docs] def get_observable(self): + return self._observable
+ + +
[docs]class MetaKiwoomOpenApiPlusEventStreamer(type(Logging), type(Observer)): + pass
+ + +
[docs]class KiwoomOpenApiPlusEventStreamer( + Observer, Logging, metaclass=MetaKiwoomOpenApiPlusEventStreamer +): + + _price_event_channels_by_stub = {} + _order_event_channels_by_stub = {} + + _lock = threading.RLock() + + def __init__(self, stub, queue): + super().__init__() + self._stub = stub + self._queue = queue + +
[docs] def on_next(self, value): + self._queue.put(value)
+ +
[docs] def on_error(self, error): + self.logger.error("Streamer.on_error(%s)", error)
+ +
[docs] def on_completed(self): + pass
+ +
[docs] def rates(self, code): + with self._lock: + if self._stub not in self._price_event_channels_by_stub: + self._price_event_channels_by_stub[ + self._stub + ] = KiwoomOpenApiPlusPriceEventChannel(self._stub) + event_channel = self._price_event_channels_by_stub[self._stub] + subscription = event_channel.get_observable_for_code(code).subscribe(self) + self.logger.debug("Subscribing rates for code %s", code) + return subscription
+ +
[docs] def events(self): + with self._lock: + if self._stub not in self._order_event_channels_by_stub: + self._order_event_channels_by_stub[ + self._stub + ] = KiwoomOpenApiPlusOrderEventChannel(self._stub) + event_channel = self._order_event_channels_by_stub[self._stub] + subscription = event_channel.get_observable().subscribe(self) + self.logger.debug("Subscribing order events") + return subscription
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KiwoomOpenApiPlusStore.html b/_modules/koapy/backtrader/KiwoomOpenApiPlusStore.html new file mode 100644 index 00000000..fc219e93 --- /dev/null +++ b/_modules/koapy/backtrader/KiwoomOpenApiPlusStore.html @@ -0,0 +1,951 @@ + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusStore — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KiwoomOpenApiPlusStore

+import collections
+import datetime
+import threading
+import time
+
+import backtrader as bt
+import numpy as np
+import pandas as pd
+
+from backtrader import TimeFrame
+from backtrader.metabase import MetaParams
+from backtrader.utils.py3 import queue
+from exchange_calendars import get_calendar
+
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import (
+    KiwoomOpenApiPlusEntrypoint,
+)
+from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import (
+    KiwoomOpenApiPlusError,
+    KiwoomOpenApiPlusNegativeReturnCodeError,
+)
+from koapy.backtrader.KiwoomOpenApiPlusEventStreamer import (
+    KiwoomOpenApiPlusEventStreamer,
+)
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class KiwoomOpenApiPlusJsonError(KiwoomOpenApiPlusNegativeReturnCodeError): + def __init__(self, code, message=None): + if isinstance(code, KiwoomOpenApiPlusError): + err = code + code = getattr( + err, "code", KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_FAIL + ) + message = err.message + super().__init__(code, message) + +
[docs] def error_response(self, description=None): + response = { + "code": self.code, + "message": self.message, + "description": description or "", + } + return response
+ + +
[docs]class KiwoomOpenApiPlusTimeFrameError(KiwoomOpenApiPlusJsonError): + def __init__(self): + super().__init__(code=597, message="Given TimeFrame is not supported")
+ + +
[docs]class HistoricalPriceRecord( + collections.namedtuple( + "HistoricalPriceRecord", ["time", "open", "high", "low", "close", "volume"] + ) +): + + __slots__ = () + + _krx_timezone = get_calendar("XKRX").tz + + @classmethod +
[docs] def from_tuple(cls, tup): + if "일자" in tup._fields: + dt = datetime.datetime.strptime(tup.일자, "%Y%m%d") + dt = cls._krx_timezone.localize(dt) + time = dt.timestamp() * (10**6) # pylint: disable=redefined-outer-name + elif "체결시간" in tup._fields: + dt = datetime.datetime.strptime(tup.체결시간, "%Y%m%d%H%M%S") + dt = cls._krx_timezone.localize(dt) + time = dt.timestamp() * (10**6) + else: + raise KiwoomOpenApiPlusError("Cannot specify time") + open = abs(float(tup.시가)) # pylint: disable=redefined-builtin + high = abs(float(tup.고가)) + low = abs(float(tup.저가)) + close = abs(float(tup.현재가)) + volume = abs(float(tup.거래량)) + return cls(time, open, high, low, close, volume)
+ + @classmethod +
[docs] def records_from_dataframe(cls, df): + return [cls.from_tuple(tup) for tup in df[::-1].itertuples()]
+ + @classmethod +
[docs] def dict_records_from_dataframe(cls, df): + return [msg._asdict() for msg in cls.records_from_dataframe(df)]
+ + +
[docs]class API: + + # 우선은 최대한 기존 Oanda 구현을 유지한채로 맞춰서 동작할 수 있도록 구현해놓고 + # 추후 동작이 되는게 확인되면 천천히 하단 API 에 맞게 최적화를 하는 방향으로 작업하는 것으로... + + _krx_timezone = get_calendar("XKRX").tz + + def __init__(self, context): + self._context = context + self._codes = self._context.GetCodeListByMarketAsList() + + def __getattr__(self, name): + return getattr(self._context, name) + +
[docs] def get_instruments_original( + self, account, instruments + ): # TODO: 계좌에 따라 시장이 다를 수 있음 + instruments = self.GetStockInfoAsDataFrame(instruments) + instruments = [tup._asdict() for tup in instruments.itertuples(index=False)] + response = {"instruments": instruments} + return response
+ +
[docs] def get_instruments(self, account, instruments): + if isinstance(instruments, str): + instruments = [instruments] + instruments = [inst for inst in instruments if inst in self._codes] + response = {"instruments": instruments} + return response
+ +
[docs] def get_history(self, trcode, inputs, dtbegin=None, dtend=None): + if trcode == "opt10079": + code = inputs["종목코드"] + interval = inputs["틱범위"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetTickStockDataAsDataFrame( + code, interval, dtend, dtbegin, adjusted_price=adjusted_price + ) + elif trcode == "opt10080": + code = inputs["종목코드"] + interval = inputs["틱범위"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetMinuteStockDataAsDataFrame( + code, interval, dtend, dtbegin, adjusted_price=adjusted_price + ) + elif trcode == "opt10081": + code = inputs["종목코드"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetDailyStockDataAsDataFrame( + code, dtend, dtbegin, adjusted_price=adjusted_price + ) + elif trcode == "opt10082": + code = inputs["종목코드"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetWeeklyStockDataAsDataFrame( + code, dtend, dtbegin, adjusted_price=adjusted_price + ) + elif trcode == "opt10083": + code = inputs["종목코드"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetMonthlyStockDataAsDataFrame( + code, dtend, dtbegin, adjusted_price=adjusted_price + ) + elif trcode == "opt10094": + code = inputs["종목코드"] + adjusted_price = inputs.get("수정주가구분") == "1" + df = self.GetYearlyStockDataAsDataFrame( + code, dtend, dtbegin, adjusted_price=adjusted_price + ) + else: + raise KiwoomOpenApiPlusError("Unexpected trcode %s" % trcode) + + candles = HistoricalPriceRecord.dict_records_from_dataframe(df) + response = {"candles": candles} + return response
+ +
[docs] def get_positions(self, account): + _summary, foreach = self.GetAccountEvaluationStatusAsSeriesAndDataFrame(account) + positions = [ + { + "instrument": tup.종목코드, + "side": "buy", + "units": float(tup.보유수량), + "avgPrice": float(tup.매입금액) / float(tup.보유수량), + } + for tup in foreach.itertuples() + ] + response = {"positions": positions} + return response
+ +
[docs] def get_account(self, account): + summary, _foreach = self.GetAccountEvaluationStatusAsSeriesAndDataFrame(account) + response = { + "marginAvail": float(summary["D+2추정예수금"]), + "balance": float(summary["추정예탁자산"]), + } + return response
+ +
[docs] def create_order(self, account, **kwargs): + request_name = "create_order({}, {})".format(account, kwargs) + screen_no = "" + account_no = account + order_type = { + "buy": 1, + "sell": 2, + }[kwargs["side"]] + code = kwargs["instrument"] + quantity = kwargs["units"] + price = kwargs.get("price", 0) + quote_type = { + "limit": "00", + "market": "03", + }[kwargs["type"]] + original_order_no = "" + responses = self.OrderCall( + request_name, + screen_no, + account_no, + order_type, + code, + quantity, + price, + quote_type, + original_order_no, + ) + + MAX_ORDER_RES_CNT = 5 + for i in range(MAX_ORDER_RES_CNT): + res = next(responses) + if ( + res.name == "OnReceiveChejanData" + and res.arguments[0].string_value == "0" # 주문접수 or 체결 + ): + break + + accept_data = dict(zip(res.single_data.names, res.single_data.values)) + result = {"orderOpened": {"id": accept_data["주문번호"]}} + return result
+ +
[docs] def close_order(self, account, oid, size, dataname): + request_name = "close_order({}, {}, {}, {})".format( + account, oid, size, dataname + ) + screen_no = "" + account_no = account + order_type = 3 if size >= 0 else 4 + code = dataname + quantity = 0 + price = 0 + quote_type = "" + original_order_no = oid + responses = self.OrderCall( + request_name, + screen_no, + account_no, + order_type, + code, + quantity, + price, + quote_type, + original_order_no, + ) + _msg = next(responses) + _tr = next(responses) + _accept = next(responses) + confirm = next(responses) + confirm_data = dict(zip(confirm.single_data.names, confirm.single_data.values)) + result = {"orderOpened": {"id": confirm_data["주문번호"]}} + return result
+ +
[docs] def get_today_quotes_by_code(self, codes=None): + if codes is None: + codes = self._codes + df = self.GetStockQuoteInfoAsDataFrame(codes) + dt = pd.to_datetime( + df["일자"].str.cat(df["체결시간"]), format="%Y%m%d%H%M%S" + ).dt.tz_localize(self._krx_timezone) + dt = dt.astype(np.int64) // 10**3 + df = pd.DataFrame( + { + "dataname": df["종목코드"], + "time": dt, + "open": df["시가"].astype(float).abs(), + "high": df["고가"].astype(float).abs(), + "low": df["저가"].astype(float).abs(), + "close": df["종가"].astype(float).abs(), + "volume": df["거래량"].astype(float).abs(), + } + ) + msgs = {tup.dataname: tup._asdict() for tup in df.itertuples(index=False)} + return msgs
+ + +
[docs]class MetaSingleton(MetaParams): + def __init__(cls, clsname, bases, dct): + super().__init__(clsname, bases, dct) + cls._singleton = None + + def __call__(cls, *args, **kwargs): + if cls._singleton is None: + cls._singleton = super().__call__(*args, **kwargs) + + return cls._singleton
+ + +
[docs]class MetaKiwoomOpenApiPlusStore(type(Logging), MetaSingleton): + pass
+ + +
[docs]class KiwoomOpenApiPlusStore(Logging, metaclass=MetaKiwoomOpenApiPlusStore): + # pylint: disable=protected-access + +
[docs] BrokerCls = None # broker class will auto register
+
[docs] DataCls = None # data class will auto register
+ +
[docs] params = ( + ("account", ""), + ("account_tmout", 60.0), # TODO: 60초마다 TR 을 날리는데 정말 이게 필요한가? + )
+ + _DTEPOCH = datetime.datetime(1970, 1, 1) + + @classmethod +
[docs] def getdata(cls, *args, **kwargs): + if cls.DataCls is None: + from koapy.backtrader.KiwoomOpenApiPlusData import KiwoomOpenApiPlusData + + cls.DataCls = KiwoomOpenApiPlusData + return cls.DataCls(*args, **kwargs) # pylint: disable=not-callable
+ + @classmethod +
[docs] def getbroker(cls, *args, **kwargs): + if cls.BrokerCls is None: + from koapy.backtrader.KiwoomOpenApiPlusBroker import KiwoomOpenApiPlusBroker + + cls.BrokerCls = KiwoomOpenApiPlusBroker + return cls.BrokerCls(*args, **kwargs) # pylint: disable=not-callable
+ + def __init__(self, context=None): + super().__init__() + + self.notifs = collections.deque() + + self._env = None + self.broker = None + + self.datas = list() + self.datanames = list() + + self._ever_started = False + self._today_quotes_by_code = None + self._today_quotes_by_code_done = threading.Event() + + self._orders = collections.OrderedDict() # map order.ref to oid + self._ordersrev = collections.OrderedDict() # map oid to order.ref + self._transpend = collections.defaultdict(collections.deque) + + if context is None: + context = KiwoomOpenApiPlusEntrypoint() + + self._context = context + self._context.EnsureConnected() + + if not self.p.account: + self.p.account = self._context.GetFirstAvailableAccount() + + self.api = API(self._context) + + self._cash = 0.0 + self._value = 0.0 + self._evt_acct = threading.Event() + + self.q_account = None + self.q_ordercreate = None + self.q_orderclose = None + + self._tmoffset = datetime.timedelta() + +
[docs] def start(self, data=None, broker=None): + if not self._ever_started: + self._ever_started = True + self._today_quotes_by_code = self.api.get_today_quotes_by_code( + self.datanames + ) + self._today_quotes_by_code_done.set() + + if data is None and broker is None: + return + + if data is not None: + self._env = data._env # pylint: disable=protected-access + self.datas.append(data) + + if self.broker is not None: + self.broker.data_started(data) + + self._today_quotes_by_code_done.wait() + + elif broker is not None: + self.broker = broker + self.streaming_events() + self.broker_threads()
+ +
[docs] def initial_today_historical_msg(self, data=None): + if data is not None: + return self._today_quotes_by_code.get(data.p.dataname)
+ +
[docs] def stop(self): + pass
+ +
[docs] def put_notification(self, msg, *args, **kwargs): + self.notifs.append((msg, args, kwargs))
+ +
[docs] def get_notifications(self): + self.notifs.append(None) + return [x for x in iter(self.notifs.popleft, None)]
+ +
[docs] def timeoffset(self): + return self._tmoffset
+ + _GRANULARITIES = { + (TimeFrame.Ticks, 1): ("opt10079", {"종목코드": "", "틱범위": "1", "수정주가구분": "1"}), + (TimeFrame.Ticks, 3): ("opt10079", {"종목코드": "", "틱범위": "3", "수정주가구분": "1"}), + (TimeFrame.Ticks, 5): ("opt10079", {"종목코드": "", "틱범위": "5", "수정주가구분": "1"}), + (TimeFrame.Ticks, 10): ("opt10079", {"종목코드": "", "틱범위": "10", "수정주가구분": "1"}), + (TimeFrame.Ticks, 30): ("opt10079", {"종목코드": "", "틱범위": "30", "수정주가구분": "1"}), + (TimeFrame.Minutes, 1): ("opt10080", {"종목코드": "", "틱범위": "1", "수정주가구분": "1"}), + (TimeFrame.Minutes, 3): ("opt10080", {"종목코드": "", "틱범위": "3", "수정주가구분": "1"}), + (TimeFrame.Minutes, 5): ("opt10080", {"종목코드": "", "틱범위": "5", "수정주가구분": "1"}), + (TimeFrame.Minutes, 10): ("opt10080", {"종목코드": "", "틱범위": "10", "수정주가구분": "1"}), + (TimeFrame.Minutes, 15): ("opt10080", {"종목코드": "", "틱범위": "15", "수정주가구분": "1"}), + (TimeFrame.Minutes, 30): ("opt10080", {"종목코드": "", "틱범위": "30", "수정주가구분": "1"}), + (TimeFrame.Minutes, 45): ("opt10080", {"종목코드": "", "틱범위": "45", "수정주가구분": "1"}), + (TimeFrame.Minutes, 60): ("opt10080", {"종목코드": "", "틱범위": "60", "수정주가구분": "1"}), + (TimeFrame.Days, 1): ("opt10081", {"종목코드": "", "기준일자": "", "수정주가구분": "1"}), + (TimeFrame.Weeks, 1): ( + "opt10082", + {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, + ), + (TimeFrame.Months, 1): ( + "opt10083", + {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, + ), + (TimeFrame.Years, 1): ( + "opt10094", + {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, + ), + } + +
[docs] def get_granularity(self, timeframe, compression, default=None): + return self._GRANULARITIES.get((timeframe, compression), default)
+ +
[docs] def get_instrument(self, dataname): + try: + insts = self.api.get_instruments(self.p.account, instruments=dataname) + except KiwoomOpenApiPlusError: + return None + + i = insts.get("instruments", [{}]) + inst = i[0] if len(i) else None + return inst
+ +
[docs] def streaming_events(self, tmout=None): + q = queue.Queue() + kwargs = {"q": q, "tmout": tmout} + + t = threading.Thread(target=self._t_streaming_listener, kwargs=kwargs) + t.daemon = True + t.start() + + t = threading.Thread(target=self._t_streaming_events, kwargs=kwargs) + t.daemon = True + t.start() + return q
+ + def _t_streaming_listener(self, q, tmout=None): + while True: + trans = q.get() + self._transaction(trans) + + def _t_streaming_events(self, q, tmout=None): + if tmout is not None: + time.sleep(tmout) + streamer = KiwoomOpenApiPlusEventStreamer(self.api, q) + streamer.events() + +
[docs] def candles(self, dataname, dtbegin, dtend, timeframe, compression): + kwargs = locals().copy() + kwargs.pop("self") + kwargs["q"] = q = queue.Queue() + t = threading.Thread(target=self._t_candles, kwargs=kwargs) + t.daemon = True + t.start() + return q
+ + def _t_candles(self, dataname, dtbegin, dtend, timeframe, compression, q): + trcode, inputs = self.get_granularity(timeframe, compression, (None, None)) + + if trcode is None: + e = KiwoomOpenApiPlusTimeFrameError() + q.put(e.error_response) + return + + inputs = inputs.copy() + inputs["종목코드"] = dataname + + if dtbegin is not None: + if "끝일자" in inputs: + inputs["끝일자"] = dtbegin.strftime("%Y%m%d") + + if dtend is not None: + if "기준일자" in inputs: + inputs["기준일자"] = dtend.strftime("%Y%m%d") + + try: + response = self.api.get_history(trcode, inputs, dtbegin, dtend) + except KiwoomOpenApiPlusError as e: + q.put(KiwoomOpenApiPlusJsonError(e).error_response()) + q.put(None) + return + + for candle in response.get("candles", []): + q.put(candle) + + q.put({}) + +
[docs] def streaming_prices(self, dataname, tmout=None): + q = queue.Queue() + kwargs = {"q": q, "dataname": dataname, "tmout": tmout} + t = threading.Thread(target=self._t_streaming_prices, kwargs=kwargs) + t.daemon = True + t.start() + return q
+ + def _t_streaming_prices(self, dataname, q, tmout): + if tmout is not None: + time.sleep(tmout) + streamer = KiwoomOpenApiPlusEventStreamer(self.api, q) + streamer.rates(dataname) + +
[docs] def get_cash(self): + return self._cash
+ +
[docs] def get_value(self): + return self._value
+ +
[docs] def get_positions(self): + try: + positions = self.api.get_positions(self.p.account) + except KiwoomOpenApiPlusError: + return None + + poslist = positions.get("positions", []) + return poslist
+ +
[docs] def broker_threads(self): + self.q_account = queue.Queue() + self.q_account.put(True) # force an immediate update + t = threading.Thread(target=self._t_account) + t.daemon = True + t.start() + + self.q_ordercreate = queue.Queue() + t = threading.Thread(target=self._t_order_create) + t.daemon = True + t.start() + + self.q_orderclose = queue.Queue() + t = threading.Thread(target=self._t_order_cancel) + t.daemon = True + t.start() + + # Wait once for the values to be set + self._evt_acct.wait(self.p.account_tmout)
+ + def _t_account(self): + while True: + try: + msg = self.q_account.get(timeout=self.p.account_tmout) + if msg is None: + break # end of thread + except queue.Empty: # tmout -> time to refresh + pass + + try: + accinfo = self.api.get_account(self.p.account) + except Exception as e: # pylint: disable=broad-except + self.put_notification(e) + continue + + try: + self._cash = accinfo["marginAvail"] + self._value = accinfo["balance"] + except KeyError: + pass + + self._evt_acct.set() + + # from below, it's related to processing orders + + _ORDEREXECS = { + bt.Order.Market: "market", + bt.Order.Limit: "limit", + bt.Order.Stop: "stop", + bt.Order.StopLimit: "stop", + } + +
[docs] def order_create(self, order, stopside=None, takeside=None, **kwargs): + okwargs = dict() + okwargs["instrument"] = order.data._dataname + okwargs["units"] = abs(order.created.size) + okwargs["side"] = "buy" if order.isbuy() else "sell" + okwargs["type"] = self._ORDEREXECS[order.exectype] + if order.exectype != bt.Order.Market: + okwargs["price"] = order.created.price + if order.valid is None: + # 1 year and datetime.max fail ... 1 month works + valid = datetime.datetime.utcnow() + datetime.timedelta(days=30) + else: + valid = order.data.num2date(order.valid) + # To timestamp with seconds precision + okwargs["expiry"] = int((valid - self._DTEPOCH).total_seconds()) + + if order.exectype == bt.Order.StopLimit: + okwargs["lowerBound"] = order.created.pricelimit + okwargs["upperBound"] = order.created.pricelimit + + if order.exectype == bt.Order.StopTrail: + okwargs["trailingStop"] = order.trailamount + + if stopside is not None: + okwargs["stopLoss"] = stopside.price + + if takeside is not None: + okwargs["takeProfit"] = takeside.price + + okwargs.update(**kwargs) # anything from the user + + self.q_ordercreate.put( + ( + order.ref, + okwargs, + ) + ) + return order
+ + _OIDSINGLE = ["orderOpened", "tradeOpened", "tradeReduced"] + _OIDMULTIPLE = ["tradesClosed"] + + def _t_order_create(self): + while True: + msg = self.q_ordercreate.get() + if msg is None: + break + + oref, okwargs = msg + try: + o = self.api.create_order(self.p.account, **okwargs) + except Exception as e: + self.logger.exception( + "Exception while create_order(%s, %s)", self.p.account, okwargs + ) + self.put_notification(e) + self.broker._reject(oref) + + # Ids are delivered in different fields and all must be fetched to + # match them (as executions) to the order generated here + oids = list() + for oidfield in self._OIDSINGLE: + if oidfield in o and "id" in o[oidfield]: + oids.append(o[oidfield]["id"]) + + for oidfield in self._OIDMULTIPLE: + if oidfield in o: + for suboidfield in o[oidfield]: + oids.append(suboidfield["id"]) + + if not oids: + self.logger.warning("Rejecting %s because no oids specified", oref) + self.broker._reject(oref) + return + + self._orders[oref] = oids[0] + self.broker._submit(oref) + if okwargs["type"] == "market": + self.broker._accept(oref) # taken immediately + + for oid in oids: + self._ordersrev[oid] = oref # maps ids to backtrader order + + # An transaction may have happened and was stored + tpending = self._transpend[oid] + tpending.append(None) # eom marker + while True: + trans = tpending.popleft() + if trans is None: + break + self._process_transaction(oid, trans) + +
[docs] def order_cancel(self, order): + self.q_orderclose.put((order.ref, order.created.size, order.data.p.dataname)) + return order
+ + def _t_order_cancel(self): + while True: + msg = self.q_orderclose.get() + if msg is None: + break + + oref, size, dataname = msg + oid = self._orders.get(oref, None) + if oid is None: + continue # the order is no longer there + try: + o = self.api.close_order(self.p.account, oid, size, dataname) + except Exception as e: + self.logger.exception("Failed to close order") + continue # not cancelled - FIXME: notify + + self.broker._cancel(oref) + + _X_ORDER_CREATE = ( + "STOP_ORDER_CREATE", + "LIMIT_ORDER_CREATE", + "MARKET_IF_TOUCHED_ORDER_CREATE", + ) + + def _transaction(self, trans): + # Invoked from Streaming Events. May actually receive an event for an + # oid which has not yet been returned after creating an order. Hence + # store if not yet seen, else forward to processer + ttype = trans["type"] + if ttype == "MARKET_ORDER_CREATE": + try: + oid = trans["tradeReduced"]["id"] + except KeyError: + try: + oid = trans["tradeOpened"]["id"] + except KeyError: + return # cannot do anything else + + elif ttype in self._X_ORDER_CREATE: + oid = trans["id"] + elif ttype == "ORDER_FILLED": + oid = trans["orderId"] + + elif ttype == "ORDER_CANCEL": + oid = trans["orderId"] + + elif ttype == "TRADE_CLOSE": + oid = trans["id"] + pid = trans["tradeId"] + if pid in self._orders and False: # Know nothing about trade + return # can do nothing + + # Skip above - at the moment do nothing + # Received directly from an event in the WebGUI for example which + # closes an existing position related to order with id -> pid + # COULD BE DONE: Generate a fake counter order to gracefully + # close the existing position + msg = ( + "Received TRADE_CLOSE for unknown order, possibly generated" + " over a different client or GUI" + ) + self.put_notification(msg, trans) + return + + else: # Go aways gracefully + try: + oid = trans["id"] + except KeyError: + oid = "None" + + msg = "Received {} with oid {}. Unknown situation" + msg = msg.format(ttype, oid) + self.put_notification(msg, trans) + return + + try: + self._process_transaction(oid, trans) + except KeyError: # not yet seen, keep as pending + self._transpend[oid].append(trans) + + _X_ORDER_FILLED = ( + "MARKET_ORDER_CREATE", + "ORDER_FILLED", + "TAKE_PROFIT_FILLED", + "STOP_LOSS_FILLED", + "TRAILING_STOP_FILLED", + ) + + def _process_transaction(self, oid, trans): + try: + oref = self._ordersrev[oid] + except KeyError: + return + + ttype = trans["type"] + + if ttype in self._X_ORDER_FILLED: + size = trans["units"] + if trans["side"] == "sell": + size = -size + price = trans["price"] + self.broker._fill(oref, size, price, ttype=ttype) + + elif ttype in self._X_ORDER_CREATE: + self.broker._accept(oref) + self._ordersrev[oid] = oref + + elif ttype in "ORDER_CANCEL": + reason = trans["reason"] + if reason == "ORDER_FILLED": + pass # individual execs have done the job + elif reason == "TIME_IN_FORCE_EXPIRED": + self.broker._expire(oref) + elif reason == "CLIENT_REQUEST": + self.broker._cancel(oref) + else: # default action ... if nothing else + self.logger.warning("Rejecting %s since it's canceled", oref) + self.broker._reject(oref)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KrxHistoricalDailyPriceData.html b/_modules/koapy/backtrader/KrxHistoricalDailyPriceData.html new file mode 100644 index 00000000..7870e902 --- /dev/null +++ b/_modules/koapy/backtrader/KrxHistoricalDailyPriceData.html @@ -0,0 +1,263 @@ + + + + + + + + koapy.backtrader.KrxHistoricalDailyPriceData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KrxHistoricalDailyPriceData

+import pandas as pd
+
+from backtrader import TimeFrame, date2num
+from backtrader.feed import DataBase
+from tqdm import tqdm
+
+from koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader import (
+    KrxHistoricalDailyPriceDataForBacktestLoader,
+)
+
+
+
[docs]class KrxHistoricalDailyPriceData(DataBase): + + # pylint: disable=no-member + +
[docs] params = ( + ("loader", None), + ("symbol", None), + ("name", None), + ("fromdate", None), + ("todate", None), + ("compression", 1), + ("timeframe", TimeFrame.Days), + ("calendar", None), + ("lazy", False), + )
+ +
[docs] lines = ( + "amount", + "marketcap", + "shares", + )
+ + def __init__(self): + super().__init__() + + assert self.p.loader + assert self.p.symbol + + assert self.p.timeframe == TimeFrame.Days + assert self.p.compression == 1 + + self.p.name = self.p.name or self.p.symbol or "" + + self._cursor = None + self._started_already = False + + if not self.p.lazy: + self.start() + + def _close_cursor(self): + if self._cursor is not None: + self._cursor.close() + self._cursor = None + + def _initialize_cursor(self): + self._close_cursor() + self._cursor = self.p.loader.load_as_cursor( + self.p.symbol, start_time=self.p.fromdate, end_time=self.p.todate + ) + +
[docs] def start(self): + if not self._started_already: + self._initialize_cursor() + self._started_already = True
+ +
[docs] def stop(self): + self._close_cursor() + self._started_already = False
+ + def _load(self): + if self._cursor is None: + return False + + try: + date, open_, high, low, close, volume, amount, marcap, shares = next( + self._cursor + ) + except StopIteration: + return False + else: + dt = pd.Timestamp(date) + + self.lines.datetime[0] = date2num(dt) + self.lines.open[0] = open_ + self.lines.high[0] = high + self.lines.low[0] = low + self.lines.close[0] = close + self.lines.volume[0] = volume + self.lines.openinterest[0] = 0.0 + + self.lines.amount[0] = amount + self.lines.marketcap[0] = marcap + self.lines.shares[0] = shares + + return True + + @classmethod +
[docs] def adddata_fromfile( + cls, + cerebro, + filename, + symbols=None, + fromdate=None, + todate=None, + progress_bar=True, + ): + loader = KrxHistoricalDailyPriceDataForBacktestLoader(filename) + if symbols is None: + symbols = loader.get_symbols() + progress = tqdm(symbols, disable=not progress_bar) + for symbol in progress: + progress.set_description("Adding Symbol [%s]" % symbol) + data = cls( + loader=loader, + symbol=symbol, + fromdate=fromdate, + todate=todate, + name=symbol, + ) # pylint: disable=unexpected-keyword-arg + cerebro.adddata(data, name=data.p.name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.html b/_modules/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.html new file mode 100644 index 00000000..a22c0e50 --- /dev/null +++ b/_modules/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.html @@ -0,0 +1,261 @@ + + + + + + + + koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite

+import pandas as pd
+
+from backtrader import TimeFrame, date2num
+from sqlalchemy import create_engine, inspect
+from tqdm import tqdm
+
+from koapy.backtrader.SQLiteData import SQLiteData
+from koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader import (
+    KrxHistoricalDailyPriceDataForBacktestLoader,
+)
+
+
+
[docs]class KrxHistoricalDailyPriceDataFromSQLite(SQLiteData): + + # pylint: disable=no-member + +
[docs] params = ( + ("engine", None), + ("symbol", None), + ("name", None), + ("fromdate", None), + ("todate", None), + ("compression", 1), + ("timeframe", TimeFrame.Days), + ("calendar", None), + ("timestampcolumn", 0), + ("timestampcolumntimezone", None), + ("lazy", False), + )
+ +
[docs] lines = ( + "amount", + "marketcap", + "shares", + )
+ + def __init__(self): + assert self.p.timeframe == TimeFrame.Days + assert self.p.compression == 1 + + self.p.tablename = self.p.tablename or self.p.symbol or None + self.p.name = self.p.name or self.p.symbol or self.p.tablename or "" + + super().__init__() + + def _load(self): + if self._cursor is None: + return False + + try: + date, open_, high, low, close, volume, amount, marcap, shares = next( + self._cursor + ) + except StopIteration: + return False + else: + dt = pd.Timestamp(date) + + self.lines.datetime[0] = date2num(dt) + self.lines.open[0] = open_ + self.lines.high[0] = high + self.lines.low[0] = low + self.lines.close[0] = close + self.lines.volume[0] = volume + self.lines.openinterest[0] = 0.0 + + self.lines.amount[0] = amount + self.lines.marketcap[0] = marcap + self.lines.shares[0] = shares + + return True + + @classmethod +
[docs] def dump_from_store( + cls, + source_filename, + dest_filename, + symbols=None, + fromdate=None, + todate=None, + progress_bar=True, + ): + loader = KrxHistoricalDailyPriceDataForBacktestLoader(source_filename) + if symbols is None: + symbols = loader.get_symbols() + engine = create_engine("sqlite:///" + dest_filename) + progress = tqdm(symbols, disable=not progress_bar) + for symbol in progress: + progress.set_description("Dumping Symbol [%s]" % symbol) + data = loader.load(symbol, start_time=fromdate, end_time=todate) + data.to_sql(symbol, engine, if_exists="replace")
+ + @classmethod +
[docs] def adddata_fromfile( + cls, + cerebro, + filename, + symbols=None, + fromdate=None, + todate=None, + progress_bar=True, + ): + engine = create_engine("sqlite:///" + filename) + inspector = inspect(engine) + if symbols is None: + symbols = inspector.get_table_names() + progress = tqdm(symbols, disable=not progress_bar) + for symbol in progress: + progress.set_description("Adding Symbol [%s]" % symbol) + # pylint: disable=unexpected-keyword-arg + data = cls( + engine=engine, + tablename=symbol, + fromdate=fromdate, + todate=todate, + symbol=symbol, + name=symbol, + ) + cerebro.adddata(data, name=data.p.name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/KrxTradingCalendar.html b/_modules/koapy/backtrader/KrxTradingCalendar.html new file mode 100644 index 00000000..82fcd4d5 --- /dev/null +++ b/_modules/koapy/backtrader/KrxTradingCalendar.html @@ -0,0 +1,199 @@ + + + + + + + + koapy.backtrader.KrxTradingCalendar — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.KrxTradingCalendar

+import datetime
+
+import pytz
+
+from backtrader.tradingcal import TradingCalendarBase
+from backtrader.utils.py3 import string_types
+from pandas import DataFrame, DatetimeIndex, Timestamp
+
+
+
[docs]class ExchangeCalendarsTradingCalendar(TradingCalendarBase): + + # pylint: disable=no-member + +
[docs] params = ( + ("calendar", None), + ("cachesize", 365), + )
+ + def __init__(self): + super().__init__() + + self._calendar = self.p.calendar + + if isinstance(self._calendar, string_types): + from exchange_calendars import get_calendar + + self._calendar = get_calendar(self._calendar) + + self.dcache = DatetimeIndex([0.0]) + self.idcache = DataFrame(index=DatetimeIndex([0.0])) + self.csize = datetime.timedelta(days=self.p.cachesize) + + def _nextday(self, day): + d = day + self._calendar.day + return d, d.isocalendar() + +
[docs] def schedule( + self, day, tz=None + ): # pylint: disable=arguments-differ,unused-argument + """ + day: expecting naive datetime.datetime day in utc timezone + tz: treat/localize internal naive datetimes to this timezone + returns: (opening, closing) naive datetime.datetime pair in utc timezone + """ + session = Timestamp(day, tz=pytz.UTC).normalize() + opening, closing = self._calendar.open_and_close_for_session(session) + opening = opening.tz.localize(None).to_pydatetime() + closing = closing.tz.localize(None).to_pydatetime() + return opening, closing
+ + +
[docs]class KrxTradingCalendar(ExchangeCalendarsTradingCalendar): + +
[docs] params = ( + ("calendar", "XKRX"), + ("cachesize", 365), + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/SQLAlchemyData.html b/_modules/koapy/backtrader/SQLAlchemyData.html new file mode 100644 index 00000000..2be67228 --- /dev/null +++ b/_modules/koapy/backtrader/SQLAlchemyData.html @@ -0,0 +1,269 @@ + + + + + + + + koapy.backtrader.SQLAlchemyData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.SQLAlchemyData

+import datetime
+
+import pandas as pd
+
+from backtrader import date2num
+from backtrader.feed import DataBase
+from sqlalchemy import MetaData, Table, create_engine, select
+
+
+
[docs]class SQLAlchemyData(DataBase): + + # pylint: disable=no-member + +
[docs] params = ( + ("url", None), + ("engine", None), + ("connection", None), + ("tablename", None), + ("timestampcolumn", 0), + ("timestampcolumntimezone", None), + ("timestampcolumnsort", False), + ("lazy", True), + )
+ + def __init__(self): + super().__init__() + + assert self.p.url + assert self.p.tablename + + self._engine = self.p.engine + self._should_dispose = False + + self._cursor = None + + if self.p.timestampcolumntimezone is None: + self.p.timestampcolumntimezone = datetime.datetime.now().astimezone().tzinfo + + self._started_already = False + + if not self.p.lazy: + self.start() + + def _dispose_engine(self): + if self._engine is not None and self._should_dispose: + self._engine.dispose() + self._engine = None + + def _initialize_engine(self): + self._dispose_engine() + + self._engine = self.p.engine + self._should_dispose = False + + if self._engine is None: + if self.p.connection is not None: + self._engine = create_engine( + self.p.url, creator=lambda: self.p.connection + ) + self._should_dispose = False + else: + self._engine = create_engine(self.p.url) + self._should_dispose = True + + assert self._engine is not None + + def _close_cursor(self): + if self._cursor is not None: + self._cursor.close() + self._cursor = None + + def _initialize_cursor(self): + self._close_cursor() + + metadata = MetaData() + table = Table(self.p.tablename, metadata, autoload_with=self._engine) + timestampcolumn = table.columns[ + self.p.timestampcolumn + ] # pylint: disable=unsubscriptable-object + statement = select(table) + + if self.p.timestampcolumnsort: + statement = statement.order_by(timestampcolumn) + + if self.p.fromdate is not None: + fromdate = pd.Timestamp(self.p.fromdate, tz=self.p.timestampcolumntimezone) + statement = statement.where(timestampcolumn >= fromdate) + + if self.p.todate is not None: + todate = pd.Timestamp(self.p.todate, tz=self.p.timestampcolumntimezone) + statement = statement.where(timestampcolumn <= todate) + + statement = statement.execution_options(stream_results=True) + + self._cursor = self._engine.execute(statement) + +
[docs] def start(self): + if not self._started_already: + self._initialize_engine() + self._initialize_cursor() + self._started_already = True
+ +
[docs] def stop(self): + self._close_cursor() + self._dispose_engine() + self._started_already = False
+ + def _load(self): + if self._cursor is None: + return False + + try: + date, open_, high, low, close, volume, openinterest = next(self._cursor) + except StopIteration: + return False + else: + dt = pd.Timestamp(date) + + self.lines.datetime[0] = date2num(dt) + self.lines.open[0] = open_ + self.lines.high[0] = high + self.lines.low[0] = low + self.lines.close[0] = close + self.lines.volume[0] = volume + self.lines.openinterest[0] = openinterest + + return True
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/SQLAlchemySQLiteData.html b/_modules/koapy/backtrader/SQLAlchemySQLiteData.html new file mode 100644 index 00000000..dcb47bc9 --- /dev/null +++ b/_modules/koapy/backtrader/SQLAlchemySQLiteData.html @@ -0,0 +1,159 @@ + + + + + + + + koapy.backtrader.SQLAlchemySQLiteData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.SQLAlchemySQLiteData

+from .SQLAlchemyData import SQLAlchemyData
+
+
+
[docs]class SQLAlchemySQLiteData(SQLAlchemyData): + + # pylint: disable=no-member + +
[docs] params = (("filename", None),)
+ + def __init__(self): + if not self.p.url: + self.p.url = "sqlite://" + + if self.p.filename: + self.p.url += "/" + self.p.filename + + super().__init__()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/backtrader/SQLiteData.html b/_modules/koapy/backtrader/SQLiteData.html new file mode 100644 index 00000000..14319788 --- /dev/null +++ b/_modules/koapy/backtrader/SQLiteData.html @@ -0,0 +1,283 @@ + + + + + + + + koapy.backtrader.SQLiteData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.backtrader.SQLiteData

+import datetime
+import sqlite3
+
+import pandas as pd
+
+from backtrader import date2num
+from backtrader.feed import DataBase
+
+
+
[docs]class SQLiteData(DataBase): + + # pylint: disable=no-member + +
[docs] params = ( + ("filename", None), + ("connection", None), + ("engine", None), + ("tablename", None), + ("timestampcolumn", 0), + ("timestampcolumntimezone", None), + ("timestampcolumnsort", False), + ("timestampcolumnformat", None), # '%Y-%m-%d %H:%M:%S.%f' + ("lazy", True), + )
+ + def __init__(self): + super().__init__() + + assert self.p.tablename + + self._connection = self.p.connection + self._should_close = False + + self._cursor = None + + if self.p.timestampcolumntimezone is None: + self.p.timestampcolumntimezone = datetime.datetime.now().astimezone().tzinfo + + self._started_already = False + + if not self.p.lazy: + self.start() + + def _close_connection(self): + if self._connection is not None and self._should_close: + self._connection.close() + self._connection = None + + def _initialize_connection(self): + self._close_connection() + + self._connection = self.p.connection + self._should_close = False + + if self._connection is None: + if self.p.engine is not None: + self._connection = self.p.engine.raw_connection() + self._should_close = True + elif self.p.filename: + self._connection = sqlite3.connect( + self.p.filename, check_same_thread=False + ) + self._should_close = True + + assert self._connection is not None + + def _close_cursor(self): + if self._cursor is not None: + self._cursor.close() + self._cursor = None + + def _initialize_cursor(self): + self._close_cursor() + + self._cursor = self._connection.cursor() + + timestampcolumn = self.p.timestampcolumn + + if isinstance(timestampcolumn, int): + self._cursor.execute("SELECT * FROM '{}' LIMIT 0".format(self.p.tablename)) + timestampcolumn = self._cursor.description[timestampcolumn][0] + + statement = "SELECT * FROM '{}'".format(self.p.tablename) + + condition_prefix = " WHERE " + parameters = [] + + if self.p.fromdate is not None: + fromdate = pd.Timestamp(self.p.fromdate, tz=self.p.timestampcolumntimezone) + if self.p.timestampcolumnformat: + fromdate = fromdate.strftime(self.p.timestampcolumnformat) + statement += condition_prefix + statement += "'{}' >= ?".format(timestampcolumn) + parameters.append(fromdate) + condition_prefix = " AND " + + if self.p.todate is not None: + todate = pd.Timestamp(self.p.todate, tz=self.p.timestampcolumntimezone) + if self.p.timestampcolumnformat: + todate = fromdate.strftime(self.p.timestampcolumnformat) + statement += condition_prefix + statement += "'{}' <= ?".format(timestampcolumn) + parameters.append(todate) + condition_prefix = " AND " + + if self.p.timestampcolumnsort: + statement += " ORDER BY '{}' ASC".format(timestampcolumn) + + self._cursor.execute(statement, parameters) + +
[docs] def start(self): + if not self._started_already: + self._initialize_connection() + self._initialize_cursor() + self._started_already = True
+ +
[docs] def stop(self): + self._close_cursor() + self._close_connection() + self._started_already = False
+ + def _load(self): + if self._cursor is None: + return False + + try: + date, open_, high, low, close, volume, openinterest = next(self._cursor) + except StopIteration: + return False + else: + dt = pd.Timestamp(date) + + self.lines.datetime[0] = date2num(dt) + self.lines.open[0] = open_ + self.lines.high[0] = high + self.lines.low[0] = low + self.lines.close[0] = close + self.lines.volume[0] = volume + self.lines.openinterest[0] = openinterest + + return True
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli.html b/_modules/koapy/cli.html new file mode 100644 index 00000000..6a60fe99 --- /dev/null +++ b/_modules/koapy/cli.html @@ -0,0 +1,537 @@ + + + + + + + + koapy.cli — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli

+"""Console script for koapy."""
+
+import os
+
+import click
+
+from koapy.cli.commands.disable import disable
+from koapy.cli.commands.enable import enable
+from koapy.cli.commands.generate import generate
+from koapy.cli.commands.get import get
+from koapy.cli.commands.install import install
+from koapy.cli.commands.serve import serve
+from koapy.cli.commands.show import show
+from koapy.cli.commands.uninstall import uninstall
+from koapy.cli.commands.update import update
+from koapy.cli.utils.credentials import get_credentials
+from koapy.cli.utils.fail_with_usage import fail_with_usage
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.config import default_encoding
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ +
[docs]help_option_names = ["-h", "--help"]
+
[docs]context_settings = dict( + help_option_names=help_option_names, +)
+ + +@click.group(context_settings=context_settings) +@click.version_option(message="%(version)s") +
[docs]def cli(): + pass
+ + +cli.add_command(disable) +cli.add_command(enable) +cli.add_command(generate) +cli.add_command(get) +cli.add_command(install) +cli.add_command(serve) +cli.add_command(show) +cli.add_command(uninstall) +cli.add_command(update) + + +@cli.command(short_help="Ensure logged in when server is up.") +@click.option( + "-i", + "--interactive", + is_flag=True, + help="Put login information with prompts. Disables auto login for manual login.", +) +@click.option( + "-d", + "--disable-auto-login", + is_flag=True, + help="Disable auto login and use credentials given explicitly from config file.", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def login(interactive, disable_auto_login, port): + credentials = get_credentials(interactive) + + from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import ( + KiwoomOpenApiPlusServiceClient, + ) + + with KiwoomOpenApiPlusServiceClient(port=port, check_timeout=1) as context: + state = context.GetConnectState() + if state == 0: + click.echo("Logging in...") + else: + click.echo("Already logged in.") + if context.IsAutoLoginEnabled(): + if not disable_auto_login: + credentials = None + context.EnsureConnected(credentials) + gubun = context.GetServerGubun() + if gubun == "1": + click.echo("Logged into Simulation server.") + else: + click.echo("Logged into Real server.")
+ + +@cli.command(short_help="Watch realtime data.") +@click.option( + "-c", + "--code", + "codes", + metavar="CODE", + multiple=True, + help="Stock code to get. Can set multiple times.", +) +@click.option( + "-i", + "--input", + metavar="FILENAME", + type=click.Path(), + help="Text or excel file containing codes. Alternative to --code option.", +) +@click.option( + "-f", + "--fid", + "fids", + metavar="FID", + multiple=True, + help="FID to get. Can set multiple times.", +) +@click.option( + "-t", "--realtype", metavar="REALTYPE", help="Real type name. Alternative to --fid." +) +@click.option( + "-o", + "--output", + metavar="FILENAME", + type=click.File("w", lazy=True), + default="-", + help="Output filename (optional).", +) +@click.option( + "-f", + "--format", + metavar="FORMAT", + type=click.Choice(["json", "md"], case_sensitive=False), + default="json", + help="Output format [json|md].", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def watch(codes, input, fids, realtype, output, format, port): + # pylint: disable=redefined-builtin + + if (codes, fids, realtype) == (tuple(), tuple(), None): + fail_with_usage() + + codes_len = len(codes) + + if codes_len == 0: + if input is None: + fail_with_usage("Either code or input should be given.") + if not os.path.exists(input): + fail_with_usage("Given input does not exist.") + + if os.path.isfile(input): + if input.endswith(".xlsx"): + import pandas as pd + + df = pd.read_excel(input, dtype=str) + code_column = "종목코드" + if code_column in df: + codes = df[code_column] + else: + codes = df.iloc[0] + codes_len = len(codes) + elif input.endswith(".txt"): + with open(input, "r", encoding=default_encoding) as f: + codes = [line.strip() for line in f] + codes_len = len(codes) + else: + fail_with_usage("Unrecognized input type.") + else: + fail_with_usage("Unrecognized input type.") + + if realtype is not None: + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( + KiwoomOpenApiPlusRealType, + ) + + fids_from_realtype = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name( + realtype + ) + fids = list(set(fids).union(set(fids_from_realtype))) + + if not codes: + fail_with_usage("No codes to watch. Set --code or --input.") + + if not fids: + fail_with_usage("Cannot infer fids to watch. Set either --fid or --realtype.") + + import datetime + + import pandas as pd + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( + KiwoomOpenApiPlusRealType, + ) + + def parse_message(message): + fids = message.single_data.names + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids + ] + values = message.single_data.values + dic = { + name: value for fid, name, value in zip(fids, names, values) if name != fid + } + series = pd.Series(dic) + return series + + if format == "json": + + def print_message(message): + click.echo(parse_message(message).to_json(), file=output) + + else: + + def print_message(message): + code = message.arguments[0].string_value + name = message.arguments[1].string_value + click.echo("[{}] [{}]".format(code, name), file=output) + click.echo("[%s]" % datetime.datetime.now(), file=output) + click.echo(parse_message(message).to_markdown(), file=output) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + for event in context.GetRealDataForCodesAsStream(codes, fids, infer_fids=True): + print_message(event)
+ + +
[docs]order_types = [ + "1", + "2", + "3", + "4", + "5", + "6", +]
+ +
[docs]quote_types = [ + "00", + "03", + "05", + "06", + "07", + "10", + "13", + "16", + "20", + "23", + "26", + "61", + "62", + "81", +]
+ + +@cli.command(short_help="Place an order.") +@click.option("--request-name", metavar="NAME") +@click.option("--screen-no", metavar="SCRNO") +@click.option("--account-no", metavar="ACCNO") +@click.option("--order-type", type=click.Choice(order_types)) +@click.option("--code", metavar="CODE") +@click.option("--quantity", metavar="QTY") +@click.option("--price", metavar="PRICE") +@click.option("--quote-type", type=click.Choice(quote_types)) +@click.option("--original-order-no", metavar="ORDERNO") +@click.option( + "-f", + "--format", + metavar="FORMAT", + type=click.Choice(["pretty", "json"], case_sensitive=False), +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def order( + request_name, + screen_no, + account_no, + order_type, + code, + quantity, + price, + quote_type, + original_order_no, + format, + port, +): + # pylint: disable=redefined-builtin + + # TODO: 주문 취소시 기존 주문에 대한 이벤트 스트림 종료되도록 + + """ + \b + [주문유형] + 1 : 신규매수 + 2 : 신규매도 + 3 : 매수취소 + 4 : 매도취소 + 5 : 매수정정 + 6 : 매도정정 + + \b + [거래구분] + 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + 00 : 지정가 + 03 : 시장가 + 05 : 조건부지정가 + 06 : 최유리지정가 + 07 : 최우선지정가 + 10 : 지정가IOC + 13 : 시장가IOC + 16 : 최유리IOC + 20 : 지정가FOK + 23 : 시장가FOK + 26 : 최유리FOK + 61 : 장전시간외종가 + 62 : 시간외단일가매매 + 81 : 장후시간외종가 + """ + + if (request_name, screen_no, account_no, order_type, code, quantity) == ( + None, + None, + None, + None, + None, + None, + ): + fail_with_usage() + + if order_type is None: + fail_with_usage() + + from google.protobuf.json_format import MessageToDict + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + if format == "json": + import json + + def print_message(message): + click.echo(json.dumps(MessageToDict(message))) + + else: + import pprint + + pp = pprint.PrettyPrinter() + + def print_message(message): + click.echo(pp.pformat(MessageToDict(message))) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + if order_type in ["3", "4"] and (account_no is None or code is None): + for account_no_candidate in context.GetAccountList(): + df = context.GetOrderLogAsDataFrame1(account_no_candidate) + if "주문번호" in df.columns: + rows = df.loc[df["주문번호"] == original_order_no, :] + if rows.shape[0] > 0: + row = rows.iloc[0, :] + if account_no is None: + account_no = row["계좌번호"] + if code is None: + code = row["종목코드"] + break + + if account_no is None: + logger.info("Account not given. Using first account available.") + account_no = context.GetFirstAvailableAccount() + + responses = context.OrderCall( + request_name, + screen_no, + account_no, + order_type, + code, + quantity, + price, + quote_type, + original_order_no, + ) + for response in responses: + print_message(response)
+ + +
[docs]def main(): + cli()
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/disable.html b/_modules/koapy/cli/commands/disable.html new file mode 100644 index 00000000..5bd7a3a5 --- /dev/null +++ b/_modules/koapy/cli/commands/disable.html @@ -0,0 +1,155 @@ + + + + + + + + koapy.cli.commands.disable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.disable

+import click
+
+from .auto_login import auto_login
+
+
+@click.group(short_help="Disable things, including auto login.")
+
[docs]def disable(): + pass
+ + +disable.add_command(auto_login) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/disable/auto_login.html b/_modules/koapy/cli/commands/disable/auto_login.html new file mode 100644 index 00000000..aa0b76e4 --- /dev/null +++ b/_modules/koapy/cli/commands/disable/auto_login.html @@ -0,0 +1,190 @@ + + + + + + + + koapy.cli.commands.disable.auto_login — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.disable.auto_login

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+
[docs]def disable_auto_login_after_login(port): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + context.DisableAutoLogin()
+ + +
[docs]def disable_auto_login_without_login(): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( + KiwoomOpenApiPlusQAxWidgetUniversalMixin, + ) + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + class GetAPIModulePathStub: + def GetAPIModulePath(self): + return API_MODULE_PATH + + class DisableAutoLoginStub( + GetAPIModulePathStub, + KiwoomOpenApiPlusQAxWidgetUniversalMixin, + ): + pass + + stub = DisableAutoLoginStub() + stub.DisableAutoLogin()
+ + +@click.command(short_help="Disable auto login.") +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option(default=5, show_default=True) +
[docs]def auto_login(port): + disable_auto_login_without_login()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/enable.html b/_modules/koapy/cli/commands/enable.html new file mode 100644 index 00000000..de82c9f3 --- /dev/null +++ b/_modules/koapy/cli/commands/enable.html @@ -0,0 +1,155 @@ + + + + + + + + koapy.cli.commands.enable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.enable

+import click
+
+from .auto_login import auto_login
+
+
+@click.group(short_help="Enable things, including auto login.")
+
[docs]def enable(): + pass
+ + +enable.add_command(auto_login) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/enable/auto_login.html b/_modules/koapy/cli/commands/enable/auto_login.html new file mode 100644 index 00000000..a59594f6 --- /dev/null +++ b/_modules/koapy/cli/commands/enable/auto_login.html @@ -0,0 +1,164 @@ + + + + + + + + koapy.cli.commands.enable.auto_login — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.enable.auto_login

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Enable auto login.")
+@click.option(
+    "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)."
+)
+@verbose_option(default=5, show_default=True)
+
[docs]def auto_login(port): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + context.EnsureAutoLoginEnabled()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/generate.html b/_modules/koapy/cli/commands/generate.html new file mode 100644 index 00000000..e43f2048 --- /dev/null +++ b/_modules/koapy/cli/commands/generate.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.generate — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.generate

+import click
+
+from .grpc import grpc
+from .openapi import openapi
+
+
+@click.group(short_help="Generate files related to grpc, openapi.")
+
[docs]def generate(): + pass
+ + +generate.add_command(grpc) +generate.add_command(openapi) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/generate/grpc.html b/_modules/koapy/cli/commands/generate/grpc.html new file mode 100644 index 00000000..a454dc2f --- /dev/null +++ b/_modules/koapy/cli/commands/generate/grpc.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.generate.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.generate.grpc

+import click
+
+from .ssl_credentials import ssl_credentials
+
+
+@click.group(short_help="Generate grpc related files.")
+
[docs]def grpc(): + pass
+ + +grpc.add_command(ssl_credentials) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/generate/grpc/ssl_credentials.html b/_modules/koapy/cli/commands/generate/grpc/ssl_credentials.html new file mode 100644 index 00000000..0f2b9d3a --- /dev/null +++ b/_modules/koapy/cli/commands/generate/grpc/ssl_credentials.html @@ -0,0 +1,388 @@ + + + + + + + + koapy.cli.commands.generate.grpc.ssl_credentials — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.generate.grpc.ssl_credentials

+import datetime
+
+import click
+
+from cryptography import x509
+from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives.asymmetric import rsa
+from cryptography.x509.oid import NameOID
+
+from koapy.config import default_encoding
+
+
+
[docs]def generate_self_signed_key_cert( + organization_name, + common_name, + key_filename=None, + cert_filename=None, + key_password=None, + country_name=None, + state_or_province_name=None, + locality_name=None, + valid_days=None, +): + # generate root ca key + root_ca_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + encryption_algorithm = serialization.NoEncryption() + if key_password is not None: + if not isinstance(key_password, bytes): + encoding = default_encoding + key_password = key_password.encode(encoding) + encryption_algorithm = serialization.BestAvailableEncryption(key_password) + root_ca_key_bytes = root_ca_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=encryption_algorithm, + ) + if key_filename is None: + key_filename = "root_ca_key.pem" + with open(key_filename, "wb") as f: + f.write(root_ca_key_bytes) + + # generate root ca cert + name_attributes = [] + if country_name is not None: + name_attributes.append(x509.NameAttribute(NameOID.COUNTRY_NAME, country_name)) + if state_or_province_name is not None: + name_attributes.append( + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state_or_province_name) + ) + if locality_name is not None: + name_attributes.append(x509.NameAttribute(NameOID.LOCALITY_NAME, locality_name)) + name_attributes += [ + x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization_name), + x509.NameAttribute(NameOID.COMMON_NAME, common_name), + ] + subject = issuer = x509.Name(name_attributes) + cert_builder = x509.CertificateBuilder() + cert_builder = cert_builder.subject_name(subject) + cert_builder = cert_builder.issuer_name(issuer) + cert_builder = cert_builder.public_key(root_ca_key.public_key()) + cert_builder = cert_builder.serial_number(x509.random_serial_number()) + if valid_days is None: + valid_days = 356 * 10 + not_valid_before = datetime.datetime.utcnow() + not_valid_after = not_valid_before + datetime.timedelta(days=valid_days) + cert_builder = cert_builder.not_valid_before(not_valid_before) + cert_builder = cert_builder.not_valid_after(not_valid_after) + cert_builder = cert_builder.add_extension( + x509.SubjectAlternativeName([x509.DNSName("localhost")]), + critical=False, + ) + root_ca_cert = cert_builder.sign(root_ca_key, hashes.SHA256()) + root_ca_cert_bytes = root_ca_cert.public_bytes(serialization.Encoding.PEM) + if cert_filename is None: + cert_filename = "root_ca_cert.pem" + with open(cert_filename, "wb") as f: + f.write(root_ca_cert_bytes)
+ + +
[docs]def generate_key_cert_signed_by_authority( + organization_name, + common_name, + alternative_dns_names=None, + key_filename=None, + csr_filename=None, + cert_filename=None, + key_password=None, + country_name=None, + state_or_province_name=None, + locality_name=None, + valid_days=None, + authority_key_filename=None, + authority_cert_filename=None, + authority_key_password=None, +): + # generate server key + key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + encryption_algorithm = serialization.NoEncryption() + if key_password is not None: + if not isinstance(key_password, bytes): + encoding = default_encoding + key_password = key_password.encode(encoding) + encryption_algorithm = serialization.BestAvailableEncryption(key_password) + key_bytes = key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=encryption_algorithm, + ) + if key_filename is None: + key_filename = "key.pem" + with open(key_filename, "wb") as f: + f.write(key_bytes) + + # generate server csr + name_attributes = [] + if country_name is not None: + name_attributes.append(x509.NameAttribute(NameOID.COUNTRY_NAME, country_name)) + if state_or_province_name is not None: + name_attributes.append( + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state_or_province_name) + ) + if locality_name is not None: + name_attributes.append(x509.NameAttribute(NameOID.LOCALITY_NAME, locality_name)) + name_attributes += [ + x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization_name), + x509.NameAttribute(NameOID.COMMON_NAME, common_name), + ] + subject = x509.Name(name_attributes) + csr_builder = x509.CertificateSigningRequestBuilder() + csr_builder = csr_builder.subject_name(subject) + if alternative_dns_names is None: + alternative_dns_names = ["localhost"] + csr_builder = csr_builder.add_extension( + x509.SubjectAlternativeName( + [x509.DNSName(name) for name in alternative_dns_names] + ), + critical=False, + ) + csr = csr_builder.sign(key, hashes.SHA256()) + csr_bytes = csr.public_bytes(serialization.Encoding.PEM) + if csr_filename is None: + csr_filename = "csr.pem" + with open(csr_filename, "wb") as f: + f.write(csr_bytes) + + # get authority key and cert + if authority_key_password is not None: + if not isinstance(authority_key_password, bytes): + encoding = default_encoding + authority_key_password = authority_key_password.encode(encoding) + if authority_key_filename is None: + authority_key_filename = "root_ca_key.pem" + with open(authority_key_filename, "rb") as f: + authority_key = serialization.load_pem_private_key( + f.read(), + password=authority_key_password, + ) + if authority_cert_filename is None: + authority_cert_filename = "root_ca_cert.pem" + with open(authority_cert_filename, "rb") as f: + authority_cert = x509.load_pem_x509_certificate(f.read()) + + # root ca signs and issues server cert from server csr + cert_builder = x509.CertificateBuilder() + cert_builder = cert_builder.subject_name(subject) + cert_builder = cert_builder.issuer_name(authority_cert.subject) + cert_builder = cert_builder.public_key(csr.public_key()) + cert_builder = cert_builder.serial_number(x509.random_serial_number()) + if valid_days is None: + valid_days = 356 + not_valid_before = datetime.datetime.utcnow() + not_valid_after = not_valid_before + datetime.timedelta(days=valid_days) + cert_builder = cert_builder.not_valid_before(not_valid_before) + cert_builder = cert_builder.not_valid_after(not_valid_after) + for extension in csr.extensions: + cert_builder = cert_builder.add_extension( + extension.value, + critical=extension.critical, + ) + cert = cert_builder.sign(authority_key, hashes.SHA256()) + cert_bytes = cert.public_bytes(serialization.Encoding.PEM) + if cert_filename is None: + cert_filename = "cert.pem" + with open(cert_filename, "wb") as f: + f.write(cert_bytes)
+ + +@click.command( + short_help="Generate crypto-related files for server/client SSL/TLS.", +) +
[docs]def ssl_credentials(): + # generate root ca key and cert + root_ca_organization_name = "Root CA" + root_ca_common_name = "localhost" + root_ca_key_filename = "root_ca_key.pem" + root_ca_cert_filename = "root_ca_cert.pem" + generate_self_signed_key_cert( + root_ca_organization_name, + root_ca_common_name, + key_filename=root_ca_key_filename, + cert_filename=root_ca_cert_filename, + ) + + # generate server key and cert + server_organization_name = "Server" + server_common_name = "localhost" + server_key_filename = "server_key.pem" + server_csr_filename = "server_csr.pem" + server_cert_filename = "server_cert.pem" + generate_key_cert_signed_by_authority( + server_organization_name, + server_common_name, + key_filename=server_key_filename, + csr_filename=server_csr_filename, + cert_filename=server_cert_filename, + authority_key_filename=root_ca_key_filename, + authority_cert_filename=root_ca_cert_filename, + ) + + # generate client key and cert + client_organization_name = "Client" + client_common_name = "localhost" + client_key_filename = "client_key.pem" + client_csr_filename = "client_csr.pem" + client_cert_filename = "client_cert.pem" + generate_key_cert_signed_by_authority( + client_organization_name, + client_common_name, + key_filename=client_key_filename, + csr_filename=client_csr_filename, + cert_filename=client_cert_filename, + authority_key_filename=root_ca_key_filename, + authority_cert_filename=root_ca_cert_filename, + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/generate/openapi.html b/_modules/koapy/cli/commands/generate/openapi.html new file mode 100644 index 00000000..88ddccfc --- /dev/null +++ b/_modules/koapy/cli/commands/generate/openapi.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.generate.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.generate.openapi

+import click
+
+from .python_stubs import python_stubs
+
+
+@click.group(short_help="Generate openapi related files.")
+
[docs]def openapi(): + pass
+ + +openapi.add_command(python_stubs) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/generate/openapi/python_stubs.html b/_modules/koapy/cli/commands/generate/openapi/python_stubs.html new file mode 100644 index 00000000..157db061 --- /dev/null +++ b/_modules/koapy/cli/commands/generate/openapi/python_stubs.html @@ -0,0 +1,222 @@ + + + + + + + + koapy.cli.commands.generate.openapi.python_stubs — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.generate.openapi.python_stubs

+import click
+
+from koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs import (
+    generate_python_stubs,
+)
+from koapy.config import default_encoding
+
+
[docs]default_dispatch_class_name = "KiwoomOpenApiPlusDispatchFunctionsGenerated"
+
[docs]default_dispatch_file_path = default_dispatch_class_name + ".py"
+ +
[docs]default_event_class_name = "KiwoomOpenApiPlusEventFunctionsGenerated"
+
[docs]default_event_file_path = default_event_class_name + ".py"
+ + +@click.command( + short_help="Generate python stubs for OpenAPI Dispatch and Event.", +) +@click.option( + "--dispatch-class-name", + metavar="NAME", + help="Name for class with Dispatch functions.", + default=default_dispatch_class_name, + show_default=True, +) +@click.option( + "--dispatch-file-path", + type=click.Path(), + help="Path for python-stub with Dispatch functions.", + default=default_dispatch_file_path, + show_default=True, +) +@click.option( + "--event-class-name", + metavar="NAME", + help="Name for class with Event functions.", + default=default_event_class_name, + show_default=True, +) +@click.option( + "--event-file-path", + type=click.Path(), + help="Path for python-stub with Event functions.", + default=default_event_file_path, + show_default=True, +) +@click.option( + "--encoding", + metavar="ENCODING", + help="Encoding for stub files.", + default=default_encoding, + show_default=True, +) +@click.option( + "--force-overwrite", + help="Force overwrite even if target file already exists.", + is_flag=True, + show_default=True, +) +
[docs]def python_stubs( + dispatch_class_name, + dispatch_file_path, + event_class_name, + event_file_path, + encoding, + force_overwrite, +): + generate_python_stubs( + dispatch_class_name=dispatch_class_name, + dispatch_file_path=dispatch_file_path, + event_class_name=event_class_name, + event_file_path=event_file_path, + encoding=encoding, + force_overwrite=force_overwrite, + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get.html b/_modules/koapy/cli/commands/get.html new file mode 100644 index 00000000..27627f7d --- /dev/null +++ b/_modules/koapy/cli/commands/get.html @@ -0,0 +1,184 @@ + + + + + + + + koapy.cli.commands.get — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get

+import click
+
+from .account_data.deposit import deposit
+from .account_data.evaluation import evaluation
+from .account_data.orders import orders
+from .account_data.userinfo import userinfo
+from .chart_data.daily import daily
+from .chart_data.minute import minute
+from .openapi_meta.errmsg import errmsg
+from .openapi_meta.modulepath import modulepath
+from .openapi_meta.realinfo import realinfo
+from .openapi_meta.trinfo import trinfo
+from .stock_meta.codelist import codelist
+from .stock_meta.stockcode import stockcode
+from .stock_meta.stockinfo import stockinfo
+from .stock_meta.stockname import stockname
+
+
+@click.group(short_help="Get various types of data.")
+
[docs]def get(): + pass
+ + +get.add_command(deposit) +get.add_command(evaluation) +get.add_command(orders) +get.add_command(userinfo) + +get.add_command(daily) +get.add_command(minute) + +get.add_command(errmsg) +get.add_command(modulepath) +get.add_command(realinfo) +get.add_command(trinfo) + +get.add_command(codelist) +get.add_command(stockcode) +get.add_command(stockinfo) +get.add_command(stockname) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/account_data/deposit.html b/_modules/koapy/cli/commands/get/account_data/deposit.html new file mode 100644 index 00000000..f520e909 --- /dev/null +++ b/_modules/koapy/cli/commands/get/account_data/deposit.html @@ -0,0 +1,176 @@ + + + + + + + + koapy.cli.commands.get.account_data.deposit — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.account_data.deposit

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Get account deposit.") +@click.option("-a", "--account", metavar="ACCNO", help="Account number.") +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def deposit(account, port): + if account is None: + logger.info("Account not given. Using first account available.") + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + if account is None: + account = context.GetAccountList()[0] + + result = context.GetDepositInfo(account) + click.echo(result.to_markdown(floatfmt=".2f"))
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/account_data/evaluation.html b/_modules/koapy/cli/commands/get/account_data/evaluation.html new file mode 100644 index 00000000..9d95130e --- /dev/null +++ b/_modules/koapy/cli/commands/get/account_data/evaluation.html @@ -0,0 +1,209 @@ + + + + + + + + koapy.cli.commands.get.account_data.evaluation — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.account_data.evaluation

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Get account evaluation.") +@click.option("-a", "--account", metavar="ACCNO", help="Account number.") +@click.option( + "-d", "--include-delisted", is_flag=True, help="Include delisted.", default=True +) +@click.option("-D", "--exclude-delisted", is_flag=True, help="Exclude delisted.") +@click.option( + "-e", "--for-each", is_flag=True, help="Show individual evaluation.", default=True +) +@click.option("-E", "--as-summary", is_flag=True, help="Show summarized evaluation.") +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port): + if account is None: + logger.info("Account not given. Using first account available.") + + if exclude_delisted: + include_delisted = False + + if as_summary: + for_each = False + lookup_type = "1" + elif for_each: + lookup_type = "2" + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + if account is None: + account = context.GetAccountList()[0] + + single, multi = context.GetAccountEvaluationStatusAsSeriesAndDataFrame( + account, include_delisted + ) + click.echo("[계좌평가현황요청] : [계좌평가현황]") + click.echo(single.to_markdown(floatfmt=".2f")) + click.echo() + click.echo("[계좌평가현황요청] : [종목별계좌평가현황]") + click.echo(multi.to_markdown()) + click.echo() + + single, multi = context.GetAccountEvaluationBalanceAsSeriesAndDataFrame( + account, lookup_type + ) + click.echo("[계좌평가잔고내역요청] : [계좌평가결과]") + click.echo(single.to_markdown(floatfmt=".2f")) + click.echo() + click.echo("[계좌평가잔고내역요청] : [계좌평가잔고개별합산]") + click.echo(multi.to_markdown())
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/account_data/orders.html b/_modules/koapy/cli/commands/get/account_data/orders.html new file mode 100644 index 00000000..a3bc66a6 --- /dev/null +++ b/_modules/koapy/cli/commands/get/account_data/orders.html @@ -0,0 +1,226 @@ + + + + + + + + koapy.cli.commands.get.account_data.orders — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.account_data.orders

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Get order history of a date.") +@click.option("-a", "--account", metavar="ACCNO", help="Account number.") +@click.option("-d", "--date", metavar="DATE", help="Date to get.") +@click.option("-r", "--reverse", is_flag=True) +@click.option("-e", "--executed-only", is_flag=True) +@click.option("-E", "--not-executed-only", is_flag=True) +@click.option("-S", "--stock-only", is_flag=True) +@click.option("-B", "--bond-only", is_flag=True) +@click.option("-s", "--sell-only", is_flag=True) +@click.option("-b", "--buy-only", is_flag=True) +@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") +@click.option("-o", "--starting-order-no", metavar="ORDERNO", help="Starting order no.") +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def orders( + account, + date, + reverse, + executed_only, + not_executed_only, + stock_only, + bond_only, + sell_only, + buy_only, + code, + starting_order_no, + port, +): + if account is None: + logger.info("Account not given. Using first account available.") + + sort_type = "1" + if reverse: + sort_type = "2" + if executed_only: + sort_type = "3" + if not_executed_only: + sort_type = "4" + asset_type = "0" + if stock_only: + asset_type = "1" + if bond_only: + asset_type = "2" + order_type = "0" + if sell_only: + order_type = "1" + if buy_only: + order_type = "2" + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + if account is None: + account = context.GetFirstAvailableAccount() + df = context.GetOrderLogAsDataFrame1(account) + click.echo("[실시간미체결요청]") + click.echo(df.to_markdown()) + click.echo() + df = context.GetOrderLogAsDataFrame2(account) + click.echo("[실시간체결요청]") + click.echo(df.to_markdown()) + click.echo() + df = context.GetOrderLogAsDataFrame3( + account, date, sort_type, asset_type, order_type, code, starting_order_no + ) + click.echo("[계좌별주문체결내역상세요청]") + click.echo(df.to_markdown())
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/account_data/userinfo.html b/_modules/koapy/cli/commands/get/account_data/userinfo.html new file mode 100644 index 00000000..e42b8ea1 --- /dev/null +++ b/_modules/koapy/cli/commands/get/account_data/userinfo.html @@ -0,0 +1,187 @@ + + + + + + + + koapy.cli.commands.get.account_data.userinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.account_data.userinfo

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get user information.")
+@click.option(
+    "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)."
+)
+@verbose_option()
+
[docs]def userinfo(port): + import pandas as pd + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + result = {} + result["보유계좌수"] = context.GetLoginInfo("ACCOUNT_CNT") + account_numbers = context.GetLoginInfo("ACCLIST").rstrip(";").split(";") + for i, accno in enumerate(account_numbers): + result["계좌번호 (%d/%s)" % (i + 1, result["보유계좌수"])] = accno + result["사용자 ID"] = context.GetLoginInfo("USER_ID") + result["사용자 명"] = context.GetLoginInfo("USER_NAME") + result["키보드보안 해지 여부"] = { + "0": "정상", + "1": "해지", + }.get(context.GetLoginInfo("KEY_BSECGB"), "알수없음") + result["방화벽 설정 여부"] = { + "0": "미설정", + "1": "설정", + "2": "해지", + }.get(context.GetLoginInfo("FIREW_SECGB"), "알수없음") + result["접속서버 구분"] = { + "1": "모의투자", + }.get(context.GetServerGubun(), "실서버") + + click.echo(pd.Series(result).to_markdown())
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/chart_data/daily.html b/_modules/koapy/cli/commands/get/chart_data/daily.html new file mode 100644 index 00000000..b5b5fb24 --- /dev/null +++ b/_modules/koapy/cli/commands/get/chart_data/daily.html @@ -0,0 +1,217 @@ + + + + + + + + koapy.cli.commands.get.chart_data.daily — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.chart_data.daily

+import click
+
+from koapy.cli.utils.fail_with_usage import fail_with_usage
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Get daily OHLCV of stocks.") +@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") +@click.option( + "-o", + "--output", + metavar="FILENAME", + type=click.Path(), + help="Output filename for code.", +) +@click.option( + "-f", + "--format", + metavar="FORMAT", + type=click.Choice(["xlsx", "sqlite3"], case_sensitive=False), + default="xlsx", + help="Output format. (default: xlsx)", +) +@click.option( + "-s", + "--start-date", + metavar="YYYY-MM-DD", + type=click.DateTime(formats=["%Y-%m-%d", "%Y%m%d"]), + help="Most recent date to get. Defaults to today or yesterday if market is open.", +) +@click.option( + "-e", + "--end-date", + metavar="YYYY-MM-DD", + type=click.DateTime(formats=["%Y-%m-%d", "%Y%m%d"]), + help="Stops if reached, not included (optional).", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def daily( + code, output, format, start_date, end_date, port +): # pylint: disable=redefined-builtin + if (code, output, start_date, end_date) == (None, None, None, None): + fail_with_usage() + + if output is None: + output = "{}.{}".format(code, format) + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + df = context.GetDailyStockDataAsDataFrame(code, start_date, end_date) + + if format == "xlsx": + df.to_excel(output) + logger.info("Saved data to file: %s", output) + elif format == "sqlite3": + from sqlalchemy import create_engine + + engine = create_engine("sqlite:///" + output) + tablename = "A" + code + df.to_sql(tablename, engine) + logger.info("Saved data to file %s with tablename %s", output, tablename)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/chart_data/minute.html b/_modules/koapy/cli/commands/get/chart_data/minute.html new file mode 100644 index 00000000..bf4c91cc --- /dev/null +++ b/_modules/koapy/cli/commands/get/chart_data/minute.html @@ -0,0 +1,242 @@ + + + + + + + + koapy.cli.commands.get.chart_data.minute — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.chart_data.minute

+import click
+
+from koapy.cli.utils.fail_with_usage import fail_with_usage
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ +
[docs]minute_intervals = [ + "1", + "3", + "5", + "10", + "15", + "30", + "45", + "60", +]
+ + +@click.command(short_help="Get minute OHLCV of stocks.") +@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") +@click.option( + "-t", + "--interval", + metavar="INTERVAL", + type=click.Choice(minute_intervals, case_sensitive=False), + help="Minute interval. Possible values are [%s]" % "|".join(minute_intervals), +) +@click.option( + "-o", + "--output", + metavar="FILENAME", + type=click.Path(), + help="Output filename for code.", +) +@click.option( + "-f", + "--format", + metavar="FORMAT", + type=click.Choice(["xlsx", "sqlite3"], case_sensitive=False), + default="xlsx", + help="Output format. (default: xlsx)", +) +@click.option( + "-s", + "--start-date", + metavar="YYYY-MM-DD['T'hh:mm:ss]", + type=click.DateTime( + formats=["%Y-%m-%d", "%Y%m%d", "%Y-%m-%dT%H:%M:%S", "%Y%m%d%H%M%S"] + ), + help="Most recent date to get. Defaults to today or yesterday if market is open.", +) +@click.option( + "-e", + "--end-date", + metavar="YYYY-MM-DD['T'hh:mm:ss]", + type=click.DateTime( + formats=["%Y-%m-%d", "%Y%m%d", "%Y-%m-%dT%H:%M:%S", "%Y%m%d%H%M%S"] + ), + help="Stops if reached, not included (optional).", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def minute( + code, interval, output, format, start_date, end_date, port +): # pylint: disable=redefined-builtin + if (code, interval, output, start_date, end_date) == (None, None, None, None, None): + fail_with_usage() + + if interval is None: + fail_with_usage("Interval is not set.") + + if output is None: + output = "{}.{}".format(code, format) + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + df = context.GetMinuteStockDataAsDataFrame(code, interval, start_date, end_date) + + if format == "xlsx": + df.to_excel(output) + logger.info("Saved data to file: %s", output) + elif format == "sqlite3": + from sqlalchemy import create_engine + + engine = create_engine("sqlite:///" + output) + tablename = "A" + code + df.to_sql(tablename, engine) + logger.info("Saved data to file %s with tablename %s", output, tablename)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/openapi_meta/errmsg.html b/_modules/koapy/cli/commands/get/openapi_meta/errmsg.html new file mode 100644 index 00000000..02960154 --- /dev/null +++ b/_modules/koapy/cli/commands/get/openapi_meta/errmsg.html @@ -0,0 +1,165 @@ + + + + + + + + koapy.cli.commands.get.openapi_meta.errmsg — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.openapi_meta.errmsg

+import click
+
+from koapy.cli.utils.fail_with_usage import fail_with_usage
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get error message for error code.")
+@click.option("-e", "--err-code", metavar="ERR", type=int, help="Error code to check.")
+@verbose_option()
+
[docs]def errmsg(err_code): + if err_code is None: + fail_with_usage() + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( + KiwoomOpenApiPlusError, + ) + + err_msg = KiwoomOpenApiPlusError.get_error_message_by_code(err_code) + click.echo("[%d] %s" % (err_code, err_msg))
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/openapi_meta/modulepath.html b/_modules/koapy/cli/commands/get/openapi_meta/modulepath.html new file mode 100644 index 00000000..79231033 --- /dev/null +++ b/_modules/koapy/cli/commands/get/openapi_meta/modulepath.html @@ -0,0 +1,159 @@ + + + + + + + + koapy.cli.commands.get.openapi_meta.modulepath — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.openapi_meta.modulepath

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get OpenApi module installation path.")
+@verbose_option()
+
[docs]def modulepath(): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( + API_MODULE_PATH, + ) + + click.echo(API_MODULE_PATH)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/openapi_meta/realinfo.html b/_modules/koapy/cli/commands/get/openapi_meta/realinfo.html new file mode 100644 index 00000000..c22b311a --- /dev/null +++ b/_modules/koapy/cli/commands/get/openapi_meta/realinfo.html @@ -0,0 +1,198 @@ + + + + + + + + koapy.cli.commands.get.openapi_meta.realinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.openapi_meta.realinfo

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get real type info.")
+@click.option(
+    "-t",
+    "--realtype",
+    "realtypes",
+    metavar="REALTYPE",
+    multiple=True,
+    help="Real type name to get (like 주식시세).",
+)
+@verbose_option()
+
[docs]def realinfo(realtypes): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( + KiwoomOpenApiPlusRealType, + ) + + def get_realtypes(): + if realtypes: + if "-" in realtypes: + with click.open_file("-", "r") as f: + for realtype in f: + yield realtype.strip() + else: + for realtype in realtypes: + yield realtype + else: + while True: + try: + realtype = click.prompt("realtype", prompt_suffix=" >>> ") + realtype = realtype.strip() + if realtype == "exit": + break + if realtype: + yield realtype + except EOFError: + break + + for realtype in get_realtypes(): + fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) + if fids: + names = [ + KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) + for fid in fids + ] + for fid, name in zip(fids, names): + click.echo(" [{}] = {}".format(fid, name)) + else: + click.echo("Given realtype is invalid")
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/openapi_meta/trinfo.html b/_modules/koapy/cli/commands/get/openapi_meta/trinfo.html new file mode 100644 index 00000000..01dcfe6c --- /dev/null +++ b/_modules/koapy/cli/commands/get/openapi_meta/trinfo.html @@ -0,0 +1,208 @@ + + + + + + + + koapy.cli.commands.get.openapi_meta.trinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.openapi_meta.trinfo

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get TR info.")
+@click.option(
+    "-t",
+    "--trcode",
+    "trcodes",
+    metavar="TRCODE",
+    multiple=True,
+    help="TR code to get (like opt10001).",
+)
+@verbose_option()
+
[docs]def trinfo(trcodes): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( + KiwoomOpenApiPlusTrInfo, + ) + + def get_codes(): + if trcodes: + if "-" in trcodes: + with click.open_file("-", "r") as f: + for code in f: + yield code.strip() + else: + for code in trcodes: + yield code + else: + while True: + try: + code = click.prompt("trcode", prompt_suffix=" >>> ") + code = code.strip() + if code == "exit": + break + if code: + yield code + except EOFError: + break + + for trcode in get_codes(): + tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(trcode) + if tr_info is not None: + click.echo("[{}] : [{}]".format(tr_info.tr_code.upper(), tr_info.name)) + click.echo(" [INPUT]") + for tr_input in tr_info.inputs: + click.echo(" %s" % tr_input.name) + if tr_info.single_outputs: + click.echo( + " [OUTPUT] [SINGLE DATA] : [%s]" % tr_info.single_outputs_name + ) + for output in tr_info.single_outputs: + click.echo(" %s" % output.name) + if tr_info.multi_outputs: + click.echo( + " [OUTPUT] [MULTI DATA] : [%s]" % tr_info.multi_outputs_name + ) + for output in tr_info.multi_outputs: + click.echo(" %s" % output.name) + else: + click.echo("Given trcode is invalid")
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/stock_meta/codelist.html b/_modules/koapy/cli/commands/get/stock_meta/codelist.html new file mode 100644 index 00000000..d182ba93 --- /dev/null +++ b/_modules/koapy/cli/commands/get/stock_meta/codelist.html @@ -0,0 +1,219 @@ + + + + + + + + koapy.cli.commands.get.stock_meta.codelist — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.stock_meta.codelist

+import click
+
+from koapy.cli.commands.get.stock_meta.codelist_interactive import codelist_interactive
+from koapy.cli.utils.verbose_option import verbose_option
+
+
[docs]market_codes = [ + "0", + "10", + "3", + "8", + "50", + "4", + "5", + "6", + "9", + "30", + "all", +]
+ + +@click.command(short_help="Get stock codes.") +@click.option( + "-m", + "--market", + "markets", + metavar="MARKET", + multiple=True, + type=click.Choice(market_codes, case_sensitive=False), + help="Stock market code to get. Can set multiple times.", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def codelist(markets, port): + """ + \b + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + """ + + if not markets and click.get_text_stream("stdin").isatty(): + return codelist_interactive() + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + codes = set() + for market in markets: + codes = codes.union(set(context.GetCodeListByMarketAsList(market))) + codes = sorted(list(codes)) + for code in codes: + click.echo(code)
+ + +
[docs]def main(): + codelist() # pylint: disable=no-value-for-parameter
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/stock_meta/codelist_interactive.html b/_modules/koapy/cli/commands/get/stock_meta/codelist_interactive.html new file mode 100644 index 00000000..690bcf2c --- /dev/null +++ b/_modules/koapy/cli/commands/get/stock_meta/codelist_interactive.html @@ -0,0 +1,387 @@ + + + + + + + + koapy.cli.commands.get.stock_meta.codelist_interactive — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.stock_meta.codelist_interactive

+import curses
+import curses.ascii
+import logging
+import unicodedata
+
+import pygtrie
+
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class MarketEntry: + def __init__(self, code, name): + self.code = code + self.name = name + self.stocks = [] + +
[docs] def to_string(self): + return "[{:2}] {}".format(self.code, self.name)
+ + +
[docs]class StockEntry: + def __init__(self, code, name): + self.code = code + self.name = name + +
[docs] def to_string(self): + return "[{}] {}".format(self.code, self.name)
+ + +
[docs]markets = [ + MarketEntry(0, "KOSPI"), + MarketEntry(10, "KOSDAQ"), + MarketEntry(3, "ELW"), + MarketEntry(8, "ETF"), + MarketEntry(50, "KONEX"), + MarketEntry(4, "MUTUAL FUND"), + MarketEntry(5, "RIGHTS OFFERING"), + MarketEntry(6, "REITS"), + MarketEntry(9, "HIGH YIELD FUND"), + MarketEntry(30, "K-OTC"), +]
+ + +
[docs]class StatusBarHandler(logging.Handler): + def __init__(self, screen, level=logging.NOTSET): + super().__init__(level) + self._screen = screen + +
[docs] def emit(self, record): + self._screen.set_footer_bar(record.getMessage())
+ + +
[docs]def screen_len(str): + l = 0 + for c in str: + if unicodedata.east_asian_width(c) in ["F", "W"]: + l += 2 + else: + l += 1 + return l
+ + +
[docs]class Screen: + def __init__(self, screen): + self._screen = screen + + curses.start_color() + curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) + + self._screen.clear() + self._screen.refresh() + + self._height, self._width = self._screen.getmaxyx() + + self._header_bar = curses.newwin(1, self._width, 0, 0) + self._header_bar.attron(curses.A_REVERSE) + self._header_bar_prefix = ">>> " + self._header_bar_text = self._header_bar_prefix + self._pad = curses.newpad(0, self._width) + self._footer_bar = curses.newwin(1, self._width, self._height - 1, 0) + self._footer_bar.attron(curses.A_REVERSE) + self._footer_text = "" + + self._exit_key = ord("q") + + self.refresh_header_bar() + self.set_footer_bar("Logs will appear here...") + + self._handler = StatusBarHandler(self) + self._logger = Logging.get_logger("koapy") + self._logger.addHandler(self._handler) + + from koapy import KiwoomOpenApiPlusEntrypoint + + self._entrypoint = KiwoomOpenApiPlusEntrypoint() + self._entrypoint.EnsureConnected() + +
[docs] def refresh_header_bar(self): + self._height, self._width = self._screen.getmaxyx() + self._header_bar.resize(1, self._width) + self._header_bar.mvwin(0, 0) + self._header_bar.addstr(0, 0, self._header_bar_text.ljust(self._width - 1)) + self._screen.move(0, screen_len(self._header_bar_text)) + self._header_bar.refresh()
+ +
[docs] def set_header_bar(self, text): + self._header_bar_text = self._header_bar_prefix + text + self.refresh_header_bar()
+ + + + + +
[docs] def show_entries(self, entries): + trie = pygtrie.CharTrie() + for entry in entries: + trie[str(entry.code)] = entry + trie[entry.name] = entry + original_entries = entries + current_entries = original_entries + k = 0 + cursor_y = 0 + scroll_y = 0 + query = "" + while k not in [curses.ascii.ESC, curses.KEY_LEFT]: + self.set_header_bar(query) + self.refresh_footer_bar() + self._height, self._width = self._screen.getmaxyx() + pad_height = self._height - 2 + pad_width = self._width + self._pad.resize(len(current_entries), pad_width) + self._pad.clear() + if k == curses.KEY_DOWN: + cursor_y = cursor_y + 1 + elif k == curses.KEY_UP: + cursor_y = cursor_y - 1 + elif k == curses.KEY_PPAGE: + prev_scroll_y = scroll_y + scroll_y = max(scroll_y - pad_height, 0) + cursor_y -= prev_scroll_y - scroll_y + elif k == curses.KEY_NPAGE: + prev_scroll_y = scroll_y + scroll_y = min( + scroll_y + pad_height, len(current_entries) - 1 - pad_height + ) + scroll_y = max(0, scroll_y) + cursor_y += scroll_y - prev_scroll_y + elif k == curses.KEY_RIGHT: + if len(current_entries) > 0: + entry = current_entries[cursor_y] + if hasattr(entry, "stocks"): + market = entry + if len(market.stocks) == 0: + stock_codes = self._entrypoint.GetCodeListByMarketAsList( + market.code + ) + stock_names = [ + self._entrypoint.GetMasterCodeName(code) + for code in stock_codes + ] + stocks = [ + StockEntry(code, name) + for code, name in zip(stock_codes, stock_names) + ] + market.stocks = stocks + self._pad.clear() + self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) + self.show_entries(market.stocks) + self._pad.clear() + self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) + k = 0 + continue + elif k in [curses.KEY_BACKSPACE, 8]: + if len(query) > 0: + query = query[:-1] + self.set_header_bar(query) + if len(query) > 0: + if trie.has_key(query) or trie.has_subtrie(query): + current_entries = trie.values(query) + else: + current_entries = original_entries + self._pad.clear() + self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) + k = 0 + continue + elif unicodedata.category(chr(k))[0] != "C": + query += chr(k) + self.set_header_bar(query) + if trie.has_key(query) or trie.has_subtrie(query): + current_entries = trie.values(query) + else: + current_entries = [] + self._pad.clear() + self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) + k = 0 + continue + cursor_y = min(len(current_entries) - 1, cursor_y) + cursor_y = max(0, cursor_y) + if k == curses.KEY_DOWN: + if cursor_y == (scroll_y + pad_height - 9): + scroll_y = cursor_y - pad_height + 10 + elif cursor_y > (scroll_y + pad_height - 2): + scroll_y = cursor_y - pad_height + 1 + elif k == curses.KEY_UP: + if cursor_y == scroll_y + 8: + scroll_y = cursor_y - 9 + elif cursor_y < scroll_y: + scroll_y = cursor_y + scroll_y = min(len(current_entries) - 1, scroll_y) + scroll_y = max(0, scroll_y) + for i, market in enumerate(current_entries): + attr = 0 + if i == cursor_y: + attr = curses.A_UNDERLINE + self._pad.addstr(i, 0, market.to_string().ljust(pad_width - 1), attr) + self._pad.refresh(scroll_y, 0, 1, 0, pad_height, pad_width - 1) + k = self._screen.getch()
+ + +
[docs]def wrapper(stdscr): + screen = Screen(stdscr) + screen.show_entries(markets)
+ + +
[docs]def codelist_interactive(): + curses.wrapper(wrapper)
+ + +
[docs]def main(): + codelist_interactive()
+ + +if __name__ == "__main__": + main() +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/stock_meta/stockcode.html b/_modules/koapy/cli/commands/get/stock_meta/stockcode.html new file mode 100644 index 00000000..a0711d58 --- /dev/null +++ b/_modules/koapy/cli/commands/get/stock_meta/stockcode.html @@ -0,0 +1,257 @@ + + + + + + + + koapy.cli.commands.get.stock_meta.stockcode — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.stock_meta.stockcode

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
[docs]market_codes = [ + "0", + "10", + "3", + "8", + "50", + "4", + "5", + "6", + "9", + "30", + "all", +]
+ + +@click.command(short_help="Get stock codes.") +@click.option( + "-n", + "--name", + "names", + metavar="NAME", + multiple=True, + help="Name of stock. Can set multiple times.", +) +@click.option( + "-m", + "--market", + "markets", + metavar="MARKET", + multiple=True, + type=click.Choice(market_codes, case_sensitive=False), + help="Stock market code to get. Can set multiple times.", +) +@click.option( + "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." +) +@verbose_option() +
[docs]def stockcode(names, markets, port): + """ + \b + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + """ + + markets_option = markets + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + if not markets: + markets = ["0"] + + codes = set() + + for market in markets: + codes = codes.union(set(context.GetCodeListByMarketAsList(market))) + + codes = sorted(list(codes)) + + if markets_option: + for code in codes: + click.echo(code) + else: + + def get_names(): + if names: + if "-" in names: + with click.open_file("-", "r") as f: + for name in f: + yield name.strip() + else: + for name in names: + yield name + else: + while True: + try: + name = click.prompt("name", prompt_suffix=" >>> ") + name = name.strip() + if name == "exit": + break + if name: + yield name + except EOFError: + break + + all_names = [context.GetMasterCodeName(code) for code in codes] + codes_by_name = dict(zip(all_names, codes)) + + for name in get_names(): + code = codes_by_name.get(name, None) + if code: + click.echo(code) + else: + click.echo("Cannot find code for given name: %s." % name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/stock_meta/stockinfo.html b/_modules/koapy/cli/commands/get/stock_meta/stockinfo.html new file mode 100644 index 00000000..853d0b17 --- /dev/null +++ b/_modules/koapy/cli/commands/get/stock_meta/stockinfo.html @@ -0,0 +1,216 @@ + + + + + + + + koapy.cli.commands.get.stock_meta.stockinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.stock_meta.stockinfo

+import click
+
+from koapy.cli.utils.fail_with_usage import fail_with_usage
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.config import default_encoding
+
+
+@click.command(short_help="Get basic information of stocks.")
+@click.option("-c", "--code", metavar="CODE", help="Stock code to get.")
+@click.option(
+    "-o",
+    "--output",
+    metavar="FILENAME",
+    type=click.Path(),
+    help="Output filename. Optional for single code (prints to console).",
+)
+@click.option(
+    "-f",
+    "--format",
+    type=click.Choice(["md", "xlsx", "json"], case_sensitive=False),
+    help="Output format. (default: md)",
+    default="md",
+    show_choices=True,
+)
+@click.option(
+    "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)."
+)
+@verbose_option()
+
[docs]def stockinfo(code, output, format, port): # pylint: disable=redefined-builtin + if (code, output) == (None, None): + fail_with_usage() + + if output is None: + if format is None: + format = "md" + else: + if format is None: + format = "xlsx" + if format == "xlsx": + if not output.endswith(".xlsx"): + output += ".xlsx" + elif format == "md": + if not output.endswith(".md"): + output += ".md" + elif format == "json": + if not output.endswith(".json"): + output += ".json" + + import pandas as pd + + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + dic = context.GetStockBasicInfoAsDict(code) + series = pd.Series(dic) + + if not output: + if format == "md": + click.echo(series.to_markdown()) + elif format == "json": + click.echo(series.to_json()) + else: + if format == "xlsx": + series.to_excel(output, header=False) + elif format == "json": + with open(output, "w", encoding=default_encoding) as f: + click.echo(series.to_json(), file=f)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/get/stock_meta/stockname.html b/_modules/koapy/cli/commands/get/stock_meta/stockname.html new file mode 100644 index 00000000..b9260705 --- /dev/null +++ b/_modules/koapy/cli/commands/get/stock_meta/stockname.html @@ -0,0 +1,196 @@ + + + + + + + + koapy.cli.commands.get.stock_meta.stockname — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.get.stock_meta.stockname

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Get name for stock codes.")
+@click.option(
+    "-c",
+    "--code",
+    "codes",
+    metavar="CODE",
+    multiple=True,
+    help="Stock code to get. Can set multiple times.",
+)
+@click.option(
+    "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)."
+)
+@verbose_option()
+
[docs]def stockname(codes, port): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + + def get_codes(): + if codes: + if "-" in codes: + with click.open_file("-", "r") as f: + for code in f: + yield code.strip() + else: + for code in codes: + yield code + else: + while True: + try: + code = click.prompt("code", prompt_suffix=" >>> ") + code = code.strip() + if code == "exit": + break + if code: + yield code + except EOFError: + break + + for code in get_codes(): + name = context.GetMasterCodeName(code) + click.echo(name)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/install.html b/_modules/koapy/cli/commands/install.html new file mode 100644 index 00000000..c6a30103 --- /dev/null +++ b/_modules/koapy/cli/commands/install.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.install — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.install

+import click
+
+from .openapi import openapi
+from .pywin32 import pywin32
+
+
+@click.group(short_help="Install openapi module and others.")
+
[docs]def install(): + pass
+ + +install.add_command(openapi) +install.add_command(pywin32) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/install/openapi.html b/_modules/koapy/cli/commands/install/openapi.html new file mode 100644 index 00000000..a3deb50e --- /dev/null +++ b/_modules/koapy/cli/commands/install/openapi.html @@ -0,0 +1,210 @@ + + + + + + + + koapy.cli.commands.install.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.install.openapi

+import contextlib
+import os
+import shutil
+import subprocess
+import tempfile
+
+import click
+
+from koapy.cli.utils.openapi import (
+    download_openapi_installer,
+    prepare_issfile_for_install,
+    run_installer_with_issfile,
+)
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Install openapi module.") +@click.option( + "-t", + "--target", + metavar="TARGET", + type=click.Path(), + default="C:\\", + help='Target directory for installation. Will create "OpenAPI" folder under this directory for install. (default: "C:\\")', +) +@click.option( + "--cleanup/--no-cleanup", + default=True, + help="Clean up temporary directory after install. (default: true)", +) +@verbose_option(default=5, show_default=True) +
[docs]def openapi(target, cleanup): + with contextlib.ExitStack() as stack: + tempdir = tempfile.mkdtemp() + logger.info("Created temporary directory: %s", tempdir) + if cleanup: + stack.callback(shutil.rmtree, tempdir) + logger.info("Registered to remove the temporary directory after install.") + installer_filename = "OpenAPISetup.exe" + installer_filepath = os.path.join(tempdir, installer_filename) + logger.info("Downloading installer: %s", installer_filepath) + download_openapi_installer(installer_filepath) + iss_filename = "setup.iss" + iss_filepath = os.path.join(tempdir, iss_filename) + logger.info("Preparing .iss file: %s", iss_filepath) + prepare_issfile_for_install(iss_filepath, target) + log_filename = "setup.log" + log_filepath = os.path.join(tempdir, log_filename) + try: + _return_code = run_installer_with_issfile( + installer_filepath, iss_filepath, log_filepath, cwd=tempdir + ) + except subprocess.CalledProcessError as e: + logger.exception( + "Failed to install openapi with return code: %d", e.returncode + ) + raise RuntimeError( + "Failed to install openapi with return code: %d" % e.returncode + ) from e + else: + logger.info("Succesfully installed openapi.")
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/install/pywin32.html b/_modules/koapy/cli/commands/install/pywin32.html new file mode 100644 index 00000000..e914deb6 --- /dev/null +++ b/_modules/koapy/cli/commands/install/pywin32.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.install.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.install.pywin32

+import click
+
+from koapy.cli.utils.pywin32 import install_pywin32
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Install pywin32 and run post install script.")
+@click.option("--version", metavar="VERSION", help="Version of pywin32 to install.")
+@verbose_option(default=5, show_default=True)
+
[docs]def pywin32(version): + install_pywin32(version)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/serve.html b/_modules/koapy/cli/commands/serve.html new file mode 100644 index 00000000..f8a97852 --- /dev/null +++ b/_modules/koapy/cli/commands/serve.html @@ -0,0 +1,185 @@ + + + + + + + + koapy.cli.commands.serve — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.serve

+import sys
+
+import click
+
+from koapy.cli.utils.grpc_options import grpc_server_and_client_options
+from koapy.cli.utils.verbose_option import full_verbose_option
+
+
+@click.command(
+    context_settings=dict(
+        ignore_unknown_options=True,
+    ),
+    short_help="Start grpc server with tray application.",
+)
+@click.pass_context
+@grpc_server_and_client_options()
+@full_verbose_option()
+@click.argument("args", nargs=-1, type=click.UNPROCESSED)
+
[docs]def serve( + ctx, + verbose, + **kwargs, +): + # reconstruct args so that only the first argument is program + # and others are real arguments + context_depth = 0 + c = ctx + while c is not None: + context_depth += 1 + c = c.parent + args = sys.argv[:1] + sys.argv[context_depth:] + + # force verbosity of created applications to follow the cli option + args.append("--verbose={}".format(verbose)) + + # call main function of manager application with the prepared args + from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication import ( + KiwoomOpenApiPlusManagerApplication, + ) + + KiwoomOpenApiPlusManagerApplication.main(args)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/show.html b/_modules/koapy/cli/commands/show.html new file mode 100644 index 00000000..3d5a6311 --- /dev/null +++ b/_modules/koapy/cli/commands/show.html @@ -0,0 +1,155 @@ + + + + + + + + koapy.cli.commands.show — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.show

+import click
+
+from .account_window import account_window
+
+
+@click.group(short_help="Show some configuration windows.")
+
[docs]def show(): + pass
+ + +show.add_command(account_window) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/show/account_window.html b/_modules/koapy/cli/commands/show/account_window.html new file mode 100644 index 00000000..8aea429b --- /dev/null +++ b/_modules/koapy/cli/commands/show/account_window.html @@ -0,0 +1,164 @@ + + + + + + + + koapy.cli.commands.show.account_window — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.show.account_window

+import click
+
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Show configuration window for auto login.")
+@click.option(
+    "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)."
+)
+@verbose_option()
+
[docs]def account_window(port): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( + KiwoomOpenApiPlusEntrypoint, + ) + + with KiwoomOpenApiPlusEntrypoint(port=port) as context: + context.EnsureConnected() + context.ShowAccountWindow()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/uninstall.html b/_modules/koapy/cli/commands/uninstall.html new file mode 100644 index 00000000..000c9b8a --- /dev/null +++ b/_modules/koapy/cli/commands/uninstall.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.cli.commands.uninstall — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.uninstall

+import click
+
+from .openapi import openapi
+from .pywin32 import pywin32
+
+
+@click.group(short_help="Uninstall openapi module and others.")
+
[docs]def uninstall(): + pass
+ + +uninstall.add_command(openapi) +uninstall.add_command(pywin32) +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/uninstall/openapi.html b/_modules/koapy/cli/commands/uninstall/openapi.html new file mode 100644 index 00000000..e705e446 --- /dev/null +++ b/_modules/koapy/cli/commands/uninstall/openapi.html @@ -0,0 +1,207 @@ + + + + + + + + koapy.cli.commands.uninstall.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.uninstall.openapi

+import contextlib
+import os
+import shutil
+import subprocess
+import tempfile
+
+import click
+
+from koapy.cli.utils.openapi import (
+    download_openapi_installer,
+    prepare_issfile_for_uninstall,
+    run_installer_with_issfile,
+)
+from koapy.cli.utils.verbose_option import verbose_option
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +@click.command(short_help="Uninstall openapi module.") +@click.option( + "--reboot/--no-reboot", + default=False, + help="Reboot after uninstall. (default: false)", +) +@click.option( + "--cleanup/--no-cleanup", + default=True, + help="Clean up temporary directory after uninstall. (default: true)", +) +@verbose_option(default=5, show_default=True) +
[docs]def openapi(reboot, cleanup): + with contextlib.ExitStack() as stack: + tempdir = tempfile.mkdtemp() + logger.info("Created temporary directory: %s", tempdir) + if cleanup: + stack.callback(shutil.rmtree, tempdir) + logger.info("Registered to remove the temporary directory after uninstall.") + installer_filename = "OpenAPISetup.exe" + installer_filepath = os.path.join(tempdir, installer_filename) + logger.info("Downloading installer: %s", installer_filepath) + download_openapi_installer(installer_filepath) + iss_filename = "setup.iss" + iss_filepath = os.path.join(tempdir, iss_filename) + logger.info("Preparing .iss file: %s", iss_filepath) + prepare_issfile_for_uninstall(iss_filepath, reboot) + log_filename = "setup.log" + log_filepath = os.path.join(tempdir, log_filename) + try: + _return_code = run_installer_with_issfile( + installer_filepath, iss_filepath, log_filepath, cwd=tempdir + ) + except subprocess.CalledProcessError as e: + logger.exception( + "Failed to uninstall openapi with return code: %d", e.returncode + ) + raise RuntimeError( + "Failed to uninstall openapi with return code: %d" % e.returncode + ) from e + else: + logger.info("Succesfully uninstalled openapi.")
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/uninstall/pywin32.html b/_modules/koapy/cli/commands/uninstall/pywin32.html new file mode 100644 index 00000000..59ec2c32 --- /dev/null +++ b/_modules/koapy/cli/commands/uninstall/pywin32.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.cli.commands.uninstall.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.uninstall.pywin32

+import click
+
+from koapy.cli.utils.pywin32 import uninstall_pywin32
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.command(short_help="Uninstall pywin32 and run post uninstall script.")
+@verbose_option(default=5, show_default=True)
+
[docs]def pywin32(): + uninstall_pywin32()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/commands/update.html b/_modules/koapy/cli/commands/update.html new file mode 100644 index 00000000..77fdfa95 --- /dev/null +++ b/_modules/koapy/cli/commands/update.html @@ -0,0 +1,197 @@ + + + + + + + + koapy.cli.commands.update — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.commands.update

+import click
+
+from koapy.cli.utils.credentials import get_credentials
+from koapy.cli.utils.verbose_option import verbose_option
+
+
+@click.group(short_help="Update openapi module and metadata.")
+
[docs]def update(): + pass
+ + +@update.command(short_help="Update openapi TR metadata.") +@verbose_option() +
[docs]def trinfo(): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( + KiwoomOpenApiPlusTrInfo, + ) + + KiwoomOpenApiPlusTrInfo.dump_trinfo_by_code()
+ + +@update.command(short_help="Update openapi realtype metadata.") +@verbose_option() +
[docs]def realtype(): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( + KiwoomOpenApiPlusRealType, + ) + + KiwoomOpenApiPlusRealType.dump_realtype_by_desc()
+ + +@update.command(short_help="Update openapi module version.") +@click.option( + "-i", "--interactive", is_flag=True, help="Put login information with prompts." +) +@verbose_option(default=5, show_default=True) +
[docs]def openapi(interactive): + from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( + KiwoomOpenApiPlusVersionUpdater, + ) + + credentials = get_credentials(interactive) + updater = KiwoomOpenApiPlusVersionUpdater(credentials) + updater.update_version_if_necessary()
+ + +@update.command(short_help="Update gRPC stub files by compiling proto files.") +
[docs]def proto(): + from koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto import ( + compile_proto, + ) + + compile_proto()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/extensions/functools.html b/_modules/koapy/cli/extensions/functools.html new file mode 100644 index 00000000..b4d82164 --- /dev/null +++ b/_modules/koapy/cli/extensions/functools.html @@ -0,0 +1,155 @@ + + + + + + + + koapy.cli.extensions.functools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.extensions.functools

+from functools import update_wrapper
+
+
+
[docs]def update_wrapper_with_click_params(wrapper, wrapped, *args, **kwargs): + click_params_wrapper = getattr(wrapper, "__click_params__", []) + click_params_wrapped = getattr(wrapped, "__click_params__", []) + click_params = click_params_wrapped + click_params_wrapper + wrapper.__click_params__ = click_params + wrapped.__click_params__ = click_params + updated_wrapper = update_wrapper(wrapper, wrapped, *args, **kwargs) + return updated_wrapper
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/extensions/parser.html b/_modules/koapy/cli/extensions/parser.html new file mode 100644 index 00000000..2b7dc0c9 --- /dev/null +++ b/_modules/koapy/cli/extensions/parser.html @@ -0,0 +1,284 @@ + + + + + + + + koapy.cli.extensions.parser — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.extensions.parser

+import sys
+
+from argparse import Namespace
+from typing import Any, Callable, List, Optional, Sequence, Tuple, TypeVar, Union
+
+import click
+
+from click import Command
+
+
[docs]Function = TypeVar("Function", bound=Callable[..., Any])
+
[docs]FunctionOrCommand = TypeVar( + "FunctionOrCommand", bound=Union[Callable[..., Any], Command] +)
+ +
[docs]ArgumentDecorator = Callable[[FunctionOrCommand], FunctionOrCommand]
+
[docs]CommandDecorator = Callable[[Function], Command]
+ + +
[docs]class ArgumentParser: +
[docs] def parse_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Namespace: + raise NotImplementedError
+ +
[docs] def parse_known_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Tuple[Namespace, List[str]]: + raise NotImplementedError
+ + +
[docs]class ClickArgumentParser(ArgumentParser): + + _unrecognized_args_attr = "args" + + def __init__( + self, + params: Sequence[ArgumentDecorator], + command: Optional[CommandDecorator] = None, + help_option_names: Optional[Sequence[str]] = None, + ): + if help_option_names is None: + help_option_names = ["-h", "--help"] + + if command is None: + command = click.command( + context_settings=dict(help_option_names=help_option_names) + ) + + self._params = params + self._command = command + self._help_option_names = help_option_names + + def _callback(self, *args, **kwargs): + return args, kwargs + + def _parse_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ignore_unknown_options: bool = False, + allow_extra_args: bool = False, + allow_interspersed_args: bool = True, + ) -> Tuple[Namespace, List[str]]: + + if args is None: + args = sys.argv[1:] + else: + args = list(args) + + if namespace is None: + namespace = Namespace() + + def callback(*args, **kwargs): + return self._callback(*args, **kwargs) + + if ignore_unknown_options: + unrecognized_args_param = click.argument( + self._unrecognized_args_attr, + nargs=-1, + type=click.UNPROCESSED, + metavar="[ARGS]...", + ) + callback = unrecognized_args_param(callback) + + for decorator in reversed(self._params): + callback = decorator(callback) + + command = self._command(callback) + context_settings = dict( + help_option_names=self._help_option_names, + ignore_unknown_options=ignore_unknown_options, + allow_extra_args=allow_extra_args, + allow_interspersed_args=allow_interspersed_args, + ) + command.context_settings.update(context_settings) + + ret = command.main(args, standalone_mode=False) + + if isinstance(ret, int): + sys.exit(ret) + + callback_args, callback_kwargs = ret + + assert len(callback_args) == 0 + + for key, value in callback_kwargs.items(): + setattr(namespace, key, value) + + unrecognized_args = [] + + if hasattr(namespace, self._unrecognized_args_attr): + unrecognized_args = getattr(namespace, self._unrecognized_args_attr) + unrecognized_args = list(unrecognized_args) + delattr(namespace, self._unrecognized_args_attr) + + return namespace, unrecognized_args + +
[docs] def parse_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Namespace: + namespace, _unrecognized_args = self._parse_args(args, namespace) + return namespace
+ +
[docs] def parse_known_args( + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[Namespace] = None, + ) -> Tuple[Namespace, List[str]]: + namespace, unrecognized_args = self._parse_args( + args, + namespace, + ignore_unknown_options=True, + ) + return namespace, unrecognized_args
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/extensions/verbose_option.html b/_modules/koapy/cli/extensions/verbose_option.html new file mode 100644 index 00000000..583bfe42 --- /dev/null +++ b/_modules/koapy/cli/extensions/verbose_option.html @@ -0,0 +1,276 @@ + + + + + + + + koapy.cli.extensions.verbose_option — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.extensions.verbose_option

+import click
+
+from click.parser import normalize_opt
+
+from koapy.cli.extensions.functools import update_wrapper_with_click_params
+
+
+
[docs]class VerboseOption(click.Option): + def __init__(self, *decls, **attrs): + self._flag_value = attrs.pop("flag_value", None) + super().__init__(*decls, **attrs) + self._parser = None + self._parser__match_long_opt = None + self._parser__match_short_opt = None + self._parser__get_value_from_state = None + + def _match_long_opt(self, opt, explicit_value, state): + # pylint: disable=protected-access + if opt in self.opts and opt in self._parser._long_opt: + option = self._parser._long_opt[opt] + option.action = "store" + self._parser__match_long_opt(opt, explicit_value, state) + + def _match_short_opt(self, arg, state): + # pylint: disable=protected-access + prefix = arg[0] + for ch in arg[1:]: + opt = normalize_opt(f"{prefix}{ch}", self._parser.ctx) + if opt in self.opts and opt in self._parser._short_opt: + option = self._parser._short_opt[opt] + option.action = "count" + self._parser__match_short_opt(arg, state) + + def _get_value_from_state(self, option_name, option, state): + # pylint: disable=protected-access + try: + value = self._parser__get_value_from_state(option_name, option, state) + except click.BadOptionUsage: + value = self._flag_value + else: + if option_name in self.opts: + if ( + isinstance(value, str) + and value[:1] in self._parser._opt_prefixes + and len(value) > 1 + ): + state.rargs.insert(0, value) + value = self._flag_value + return value + + def _patch_parser(self, parser): + # pylint: disable=protected-access + self._parser = parser + self._parser__match_short_opt = self._parser._match_short_opt + self._parser._match_short_opt = self._match_short_opt + self._parser__match_long_opt = self._parser._match_long_opt + self._parser._match_long_opt = self._match_long_opt + self._parser__get_value_from_state = self._parser._get_value_from_state + self._parser._get_value_from_state = self._get_value_from_state + +
[docs] def add_to_parser(self, parser, ctx): + self._patch_parser(parser) + super().add_to_parser(parser, ctx)
+ + +
[docs]def verbose_flag_option( + default=0, + flag_value=1, + show_default=False, + metavar="[0...5]", + help="Set verbosity level.", +): + # pylint: disable=redefined-builtin + return click.option( + "-v", + "--verbose", + type=int, + default=default, + flag_value=flag_value, + show_default=show_default, + metavar=metavar, + help=help, + cls=VerboseOption, + )
+ + +
[docs]def no_verbose_flag_option( + help="Force zero verbosity.", +): + # pylint: disable=redefined-builtin + return click.option( + "-s", + "--no-verbose", + "--slient", + is_flag=True, + default=False, + help=help, + )
+ + +
[docs]def verbose_option( + dest="verbose", + default=0, + flag_value=1, + callback=None, + expose_value=False, + show_default=False, +): + def decorator(f): + @click.pass_context + @verbose_flag_option( + default=default, + flag_value=flag_value, + show_default=show_default, + ) + @no_verbose_flag_option() + def new_func(ctx, *args, **kwargs): + verbose = kwargs.pop("verbose") + no_verbose = kwargs.pop("no_verbose") + if no_verbose: + verbose = 0 + if expose_value: + kwargs[dest] = verbose + if callable(callback): + param = ctx.params.get("verbose") + value = verbose + callback(ctx, param, value) + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper_with_click_params(new_func, f) + + return decorator
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/credentials.html b/_modules/koapy/cli/utils/credentials.html new file mode 100644 index 00000000..72a2eb5d --- /dev/null +++ b/_modules/koapy/cli/utils/credentials.html @@ -0,0 +1,250 @@ + + + + + + + + koapy.cli.utils.credentials — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.credentials

+import os
+
+import click
+
+from koapy.config import (
+    config,
+    config_from_dict,
+    default_user_config_filepath,
+    save_config,
+    user_config,
+)
+
+
+
[docs]def prompt_credentials(): + credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") + + default_user_id = credentials["user_id"] + default_user_password = credentials["user_password"] + default_server = "simulation" if credentials["is_simulation"] else "real" + default_cert_password = credentials["cert_password"] + + user_id = click.prompt("User ID", default=default_user_id) + user_password = click.prompt( + "User Password", + hide_input=True, + default=default_user_password, + show_default=False, + ) + is_simulation = ( + click.prompt( + "Server Type", + type=click.Choice(["real", "simulation"], case_sensitive=False), + default=default_server, + ) + == "simulation" + ) + if is_simulation: + cert_password = default_cert_password + else: + cert_password = click.prompt( + "Cert Password", + hide_input=True, + default=default_cert_password, + show_default=False, + ) + account_count = click.prompt("Account Count", type=int, default=1) + account_passwords = {} + for _ in range(account_count): + account_number = click.prompt("Account Number", default="0000000000") + account_password = click.prompt( + "Account Password", + hide_input=True, + default="0000", + show_default=False, + ) + account_passwords[account_number] = account_password + + credentials = { + "user_id": user_id, + "user_password": user_password, + "cert_password": cert_password, + "is_simulation": is_simulation, + "account_passwords": account_passwords, + } + credentials = config_from_dict(credentials) + + return credentials
+ + +
[docs]def get_credentials(interactive=False): + if not interactive: + credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") + else: + credentials = prompt_credentials() + save_credentials = ( + click.prompt( + "Save credentials info into a config file?", + type=click.Choice(["y", "n"], case_sensitive=False), + default="n", + ) + == "y" + ) + if save_credentials: + config_path = click.prompt( + "Path to save config file", default=default_user_config_filepath + ) + + if os.path.exists(config_path): + should_write = ( + click.prompt( + "The file already exists, overwrite?", + type=click.Choice(["y", "n"], case_sensitive=False), + default="n", + ) + == "y" + ) + else: + should_write = True + + if should_write: + user_config.put( + "koapy.backend.kiwoom_open_api_plus.credentials", credentials + ) + save_config(config_path, user_config) + + return credentials
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/fail_with_usage.html b/_modules/koapy/cli/utils/fail_with_usage.html new file mode 100644 index 00000000..bbdb4f0e --- /dev/null +++ b/_modules/koapy/cli/utils/fail_with_usage.html @@ -0,0 +1,171 @@ + + + + + + + + koapy.cli.utils.fail_with_usage — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.fail_with_usage

+import click
+
+
+
[docs]def get_help(ctx): + return ctx.get_help()
+ + +
[docs]def get_help_without_usage(ctx): + formatter = ctx.make_formatter() + command = ctx.command + command.format_help_text(ctx, formatter) + command.format_options(ctx, formatter) + command.format_epilog(ctx, formatter) + help_without_usage = formatter.getvalue().rstrip("\n") + return help_without_usage
+ + +
[docs]def fail_with_usage(message=None, ctx=None): + if ctx is None: + ctx = click.get_current_context() + if message is not None: + click.UsageError(message, ctx).show() + click.echo() + click.echo(get_help_without_usage(ctx)) + else: + click.echo(get_help(ctx)) + ctx.exit(click.UsageError.exit_code)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/grpc_options.html b/_modules/koapy/cli/utils/grpc_options.html new file mode 100644 index 00000000..9cb80d68 --- /dev/null +++ b/_modules/koapy/cli/utils/grpc_options.html @@ -0,0 +1,528 @@ + + + + + + + + koapy.cli.utils.grpc_options — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.grpc_options

+import click
+
+from koapy.cli.extensions.functools import update_wrapper_with_click_params
+from koapy.cli.extensions.parser import ClickArgumentParser
+from koapy.cli.utils.verbose_option import full_verbose_option
+from koapy.config import config
+
+# grpc configs for default values
+
[docs]grpc_config = config.get("koapy.backend.kiwoom_open_api_plus.grpc")
+ +
[docs]default_server_bind_address = ( + grpc_config.get("server.bind_address") + or grpc_config.get("server.host") + or grpc_config.get("host") +)
+
[docs]default_server_host = default_server_bind_address
+
[docs]default_server_port = grpc_config.get("server.port") or grpc_config.get("port")
+ +
[docs]default_client_host = grpc_config.get("client.host") or grpc_config.get("host")
+
[docs]default_client_port = grpc_config.get("client.port") or grpc_config.get("port")
+ +
[docs]default_common_host = grpc_config.get("host") or grpc_config.get("client.host")
+
[docs]default_common_port = ( + grpc_config.get("port") + or grpc_config.get("server.port") + or grpc_config.get("client.port") +)
+ + +# server specific options +
[docs]server_bind_address_option = click.option( + "--bind-address", + "--host", + metavar="ADDRESS", + help="Host address of gRPC server to bind.", + default=default_server_bind_address, + show_default=True, +)
+
[docs]server_port_option = click.option( + "--port", + metavar="PORT", + type=int, + help="Port number of gRPC server to bind.", + default=default_server_port, + show_default=True, +)
+
[docs]server_key_file_option = click.option( + "--key-file", + type=click.Path(), + help="PEM encoded private key file for server SSL/TLS.", +)
+
[docs]server_cert_file_option = click.option( + "--cert-file", + type=click.Path(), + help="PEM encoded certificate chain file for server SSL/TLS.", +)
+
[docs]server_root_certs_file_option = click.option( + "--root-certs-file", + type=click.Path(), + help=""" + PEM encoded client root certificates file for client authentication. + Assumes --require-client-auth flag is set if this option is given, + unless --no-require-client-auth flag is set explicitly. + """, +)
+
[docs]server_require_client_auth_option = click.option( + "--require-client-auth", + help="Require clients to be authenticated, root certificates are required.", + is_flag=True, +)
+
[docs]server_no_require_client_auth_option = click.option( + "--no-require-client-auth", + help="Force not to require clients to be authenticated, even if root certificates are given.", + is_flag=True, +)
+ +
[docs]server_options = [ + server_bind_address_option, + server_port_option, + server_key_file_option, + server_cert_file_option, + server_root_certs_file_option, + server_require_client_auth_option, + server_no_require_client_auth_option, +]
+ + +# client specific options +
[docs]client_host_option = click.option( + "--host", + metavar="ADDRESS", + help="Host address of gRPC server to connect.", + default=default_client_host, + show_default=True, +)
+
[docs]client_port_option = click.option( + "--port", + metavar="PORT", + type=int, + help="Port number of gRPC server to connect.", + default=default_client_port, + show_default=True, +)
+
[docs]client_enable_ssl_option = click.option( + "--enable-ssl", + help=""" + Enable SSL/TLS for gRPC connection. + If --root-certs-file option is not given, + will retrieve them from a default location chosen by gRPC runtime. + """, + is_flag=True, +)
+
[docs]client_root_certs_file_option = click.option( + "--root-certs-file", + type=click.Path(), + help="PEM encoded root certificates file for SSL/TLS.", +)
+
[docs]client_key_file_option = click.option( + "--key-file", + type=click.Path(), + help="PEM encoded private key file for client authentication.", +)
+
[docs]client_cert_file_option = click.option( + "--cert-file", + type=click.Path(), + help="PEM encoded certificate chain file for client authentication.", +)
+ +
[docs]client_options = [ + client_host_option, + client_port_option, + client_enable_ssl_option, + client_root_certs_file_option, + client_key_file_option, + client_cert_file_option, +]
+ + +# server and client options (resolving option conflicts) +
[docs]server_and_client_bind_address_option = click.option( + "--bind-address", + "--server-host", + metavar="ADDRESS", + help="Host address of gRPC server to bind.", + default=default_server_bind_address, + show_default=True, +)
+
[docs]server_and_client_host_option = click.option( + "--host", + "--client-host", + metavar="ADDRESS", + help="Host address of gRPC server to connect.", + default=default_client_host, + show_default=True, +)
+
[docs]server_and_client_port_option = click.option( + "--port", + metavar="PORT", + type=int, + help="Port number of gRPC server to bind and connect.", + default=default_common_port, + show_default=True, +)
+
[docs]server_and_client_enable_ssl_option = click.option( + "--enable-ssl", + help=""" + Enable SSL/TLS for gRPC connection. + If --client-root-certs-file option is not given, + will retrieve them from a default location chosen by gRPC runtime. + """, + is_flag=True, + show_default=True, +)
+
[docs]server_and_client_server_key_file_option = click.option( + "--server-key-file", + type=click.Path(), + help="PEM encoded private key file for server SSL/TLS.", +)
+
[docs]server_and_client_server_cert_file_option = click.option( + "--server-cert-file", + type=click.Path(), + help="PEM encoded certificate chain file for server SSL/TLS.", +)
+
[docs]server_and_client_server_root_certs_file_option = click.option( + "--server-root-certs-file", + type=click.Path(), + help=""" + PEM encoded client root certificates file for client authentication. + Assumes --require-client-auth flag is set if this option is given, + unless --no-require-client-auth flag is set explicitly. + """, +)
+
[docs]server_and_client_require_client_auth_option = click.option( + "--require-client-auth", + help="Require clients to be authenticated, root certificates are required.", + is_flag=True, +)
+
[docs]server_and_client_no_require_client_auth_option = click.option( + "--no-require-client-auth", + help="Foce not to require clients to be authenticated, even if root certificates are given.", + is_flag=True, +)
+
[docs]server_and_client_client_root_certs_file_option = click.option( + "--client-root-certs-file", + type=click.Path(), + help="PEM encoded root certificates file for SSL/TLS.", +)
+
[docs]server_and_client_client_key_file_option = click.option( + "--client-key-file", + type=click.Path(), + help="PEM encoded private key file for client authentication.", +)
+
[docs]server_and_client_client_cert_file_option = click.option( + "--client-cert-file", + type=click.Path(), + help="PEM encoded certificate chain file for client authentication.", +)
+ +
[docs]server_and_client_options = [ + server_and_client_bind_address_option, + server_and_client_host_option, + server_and_client_port_option, + server_and_client_enable_ssl_option, + server_and_client_server_key_file_option, + server_and_client_server_cert_file_option, + server_and_client_server_root_certs_file_option, + server_and_client_require_client_auth_option, + server_and_client_no_require_client_auth_option, + server_and_client_client_root_certs_file_option, + server_and_client_client_key_file_option, + server_and_client_client_cert_file_option, +]
+ + +
[docs]def grpc_server_options(): + def decorator(f): + @click.pass_context + @server_bind_address_option + @server_port_option + @server_key_file_option + @server_cert_file_option + @server_root_certs_file_option + @server_require_client_auth_option + @server_no_require_client_auth_option + def new_func(ctx: click.Context, *args, **kwargs): + key_file = kwargs.get("key_file") + cert_file = kwargs.get("cert_file") + root_certs_file = kwargs.get("root_certs_file") + require_client_auth = kwargs.get("require_client_auth") + no_require_client_auth = kwargs.pop("no_require_client_auth") + + # both --key-file and --cert-file should be given + if bool(key_file) != bool(cert_file): + ctx.fail("both --key-file and --cert-file should be given.") + + # assume --require-client-auth flag is set if --root-certs-file is given + if root_certs_file is not None: + require_client_auth = True + kwargs["require_client_auth"] = require_client_auth + + # value of --require-client-auth flag should be false if --no-require-client-auth flag is set + if no_require_client_auth: + require_client_auth = False + kwargs["require_client_auth"] = require_client_auth + + # --require-client-auth flag is set but no --root-certs-file was given + if require_client_auth and root_certs_file is None: + ctx.fail( + "--require-client-auth flag is set but no --root-certs-file was given." + ) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper_with_click_params(new_func, f) + + return decorator
+ + +
[docs]def grpc_client_options(): + def decorator(f): + @click.pass_context + @client_host_option + @client_port_option + @client_enable_ssl_option + @client_root_certs_file_option + @client_key_file_option + @client_cert_file_option + def new_func(ctx: click.Context, *args, **kwargs): + enable_ssl = kwargs.get("enable_ssl") + root_certs_file = kwargs.get("root_certs_file") + key_file = kwargs.get("key_file") + cert_file = kwargs.get("cert_file") + + # assume --enable-ssl flag is set if --root-certs-file is given + if root_certs_file is not None: + enable_ssl = True + kwargs["enable_ssl"] = enable_ssl + + # both --key-file and --cert-file should be given + if bool(key_file) != bool(cert_file): + ctx.fail("both --key-file and --cert-file should be given.") + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper_with_click_params(new_func, f) + + return decorator
+ + +
[docs]def grpc_server_and_client_options(): + def decorator(f): + @click.pass_context + @server_and_client_bind_address_option + @server_and_client_host_option + @server_and_client_port_option + @server_and_client_enable_ssl_option + @server_and_client_server_key_file_option + @server_and_client_server_cert_file_option + @server_and_client_server_root_certs_file_option + @server_and_client_require_client_auth_option + @server_and_client_no_require_client_auth_option + @server_and_client_client_root_certs_file_option + @server_and_client_client_key_file_option + @server_and_client_client_cert_file_option + def new_func(ctx: click.Context, *args, **kwargs): + # server related options and logics + key_file = kwargs.get("server_key_file") + cert_file = kwargs.get("server_cert_file") + root_certs_file = kwargs.get("server_root_certs_file") + require_client_auth = kwargs.get("require_client_auth") + no_require_client_auth = kwargs.pop("no_require_client_auth") + + # both --key-file and --cert-file should be given + if bool(key_file) != bool(cert_file): + ctx.fail( + "both --server-key-file and --server-cert-file should be given." + ) + + # assume --require-client-auth flag is set if --root-certs-file is given + if root_certs_file is not None: + require_client_auth = True + kwargs["require_client_auth"] = require_client_auth + + # value of --require-client-auth flag should be false if --no-require-client-auth flag is set + if no_require_client_auth: + require_client_auth = False + kwargs["require_client_auth"] = require_client_auth + + # --require-client-auth flag is set but no --root-certs-file was given + if require_client_auth and root_certs_file is None: + ctx.fail( + "--require-client-auth flag is set but no --server-root-certs-file was given." + ) + + # client related options and logics + enable_ssl = kwargs.get("enable_ssl") + root_certs_file = kwargs.get("client_root_certs_file") + key_file = kwargs.get("client_key_file") + cert_file = kwargs.get("client_cert_file") + + # assume --enable-ssl flag is set if --root-certs-file is given + if root_certs_file is not None: + enable_ssl = True + kwargs["enable_ssl"] = enable_ssl + + # both --key-file and --cert-file should be given + if bool(key_file) != bool(cert_file): + ctx.fail( + "both --client-key-file and --client-cert-file should be given." + ) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper_with_click_params(new_func, f) + + return decorator
+ + +
[docs]server_argument_parser = ClickArgumentParser(server_options + [full_verbose_option()])
+
[docs]client_argument_parser = ClickArgumentParser(client_options + [full_verbose_option()])
+ +
[docs]server_and_client_argument_parser = ClickArgumentParser( + server_and_client_options + [full_verbose_option()] +)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/openapi.html b/_modules/koapy/cli/utils/openapi.html new file mode 100644 index 00000000..b6cb5787 --- /dev/null +++ b/_modules/koapy/cli/utils/openapi.html @@ -0,0 +1,216 @@ + + + + + + + + koapy.cli.utils.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.openapi

+import os
+import shutil
+import subprocess
+
+import requests
+
+from koapy.utils.logging import get_logger
+from koapy.utils.subprocess import quote
+
+
[docs]logger = get_logger(__name__)
+ +
[docs]iss_file_encoding = "euc-kr"
+ + +
[docs]def download_openapi_installer(filepath): + url = "https://download.kiwoom.com/web/openapi/OpenAPISetup.exe" + response = requests.get(url) + with open(filepath, "wb") as f: + f.write(response.content)
+ + +
[docs]def prepare_issfile_for_install(filepath, target=None): + iss_filedir = os.path.join( + os.path.dirname(__file__), + "../../backend/kiwoom_open_api_plus/data/scripts/", + ) + iss_filename = "install.iss" + iss_filepath = os.path.join(iss_filedir, iss_filename) + shutil.copy(iss_filepath, filepath) + if target is not None: + with open(filepath, "r", encoding=iss_file_encoding) as f: + lines = [line for line in f] + for i, line in enumerate(lines): + if line.startswith("szDir="): + lines[i] = "szDir={}\n".format(target) + break + with open(filepath, "w", encoding=iss_file_encoding) as f: + for line in lines: + f.write(line)
+ + +
[docs]def prepare_issfile_for_uninstall(filepath, reboot=False): + iss_filedir = os.path.join( + os.path.dirname(__file__), + "../../backend/kiwoom_open_api_plus/data/scripts/", + ) + iss_filename = "uninstall.iss" + iss_filepath = os.path.join(iss_filedir, iss_filename) + shutil.copy(iss_filepath, filepath) + if reboot: + with open(filepath, "r", encoding=iss_file_encoding) as f: + lines = [line for line in f] + for i, line in enumerate(lines): + if line.startswith("BootOption="): + boot_option = 3 + lines[i] = "BootOption={}\n".format(boot_option) + break + with open(filepath, "w", encoding=iss_file_encoding) as f: + for line in lines: + f.write(line)
+ + +
[docs]def run_installer_with_issfile(installer, issfile, logfile=None, cwd=None): + cmd = [quote(installer), "/s", "/f1{}".format(quote(issfile))] + if logfile is not None: + cmd.extend(["/f2{}".format(quote(logfile))]) + # should use shell=True in order not to escape quotes in args + logger.info("Running command: %s", " ".join(cmd)) + proc = subprocess.run(" ".join(cmd), shell=True, check=False, cwd=cwd) + if proc.returncode < 0: + raise subprocess.CalledProcessError(proc.returncode, " ".join(cmd)) + return proc.returncode
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/pywin32.html b/_modules/koapy/cli/utils/pywin32.html new file mode 100644 index 00000000..138659cc --- /dev/null +++ b/_modules/koapy/cli/utils/pywin32.html @@ -0,0 +1,191 @@ + + + + + + + + koapy.cli.utils.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.pywin32

+import os
+import subprocess
+import sys
+import tempfile
+
+import requests
+
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +
[docs]def get_pywin32_postinstall_script(filepath): + url = ( + "https://raw.githubusercontent.com/mhammond/pywin32/main/pywin32_postinstall.py" + ) + response = requests.get(url) + with open(filepath, "wb") as f: + f.write(response.content)
+ + +
[docs]def install_pywin32(version=None): + if version is None: + version = "304" + cmd = ["pip", "install", "pywin32>={}".format(version)] + logger.info("Running command: %s", subprocess.list2cmdline(cmd)) + subprocess.check_call(cmd) + with tempfile.TemporaryDirectory() as tempdir: + script_filename = "pywin32_postinstall.py" + script_filepath = os.path.join(tempdir, script_filename) + get_pywin32_postinstall_script(script_filepath) + cmd = [sys.executable, script_filepath, "-install"] + logger.info("Running command: %s", subprocess.list2cmdline(cmd)) + subprocess.check_call(cmd)
+ + +
[docs]def uninstall_pywin32(): + with tempfile.TemporaryDirectory() as tempdir: + script_filename = "pywin32_postinstall.py" + script_filepath = os.path.join(tempdir, script_filename) + get_pywin32_postinstall_script(script_filepath) + cmd = [sys.executable, script_filepath, "-remove"] + logger.info("Running command: %s", subprocess.list2cmdline(cmd)) + subprocess.check_call(cmd) + cmd = ["pip", "uninstall", "pywin32"] + logger.info("Running command: %s", subprocess.list2cmdline(cmd)) + subprocess.check_call(cmd)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/cli/utils/verbose_option.html b/_modules/koapy/cli/utils/verbose_option.html new file mode 100644 index 00000000..8f89843b --- /dev/null +++ b/_modules/koapy/cli/utils/verbose_option.html @@ -0,0 +1,171 @@ + + + + + + + + koapy.cli.utils.verbose_option — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.cli.utils.verbose_option

+from koapy.cli.extensions.verbose_option import (
+    verbose_option as extensions_verbose_option,
+)
+from koapy.utils.logging import set_verbosity
+
+
[docs]full_verbosity = 5
+ + +
[docs]def verbose_option_callback(ctx, param, value): + set_verbosity(value)
+ + +
[docs]def verbose_option(*args, **kwargs): + if "callback" not in kwargs: + kwargs["callback"] = verbose_option_callback + return extensions_verbose_option(*args, **kwargs)
+ + +
[docs]def full_verbose_option(*args, **kwargs): + default_kwargs = dict( + default=full_verbosity, + show_default=True, + expose_value=True, + ) + kwargs = dict(kwargs) + kwargs.update(default_kwargs) + return verbose_option(*args, **kwargs)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/compat/pyside2.html b/_modules/koapy/compat/pyside2.html new file mode 100644 index 00000000..e7771010 --- /dev/null +++ b/_modules/koapy/compat/pyside2.html @@ -0,0 +1,175 @@ + + + + + + + + koapy.compat.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.compat.pyside2

+import os
+
+from koapy.config import config, debug
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ +# Set QT_API environment variable for correct Qt backend usage +os.environ["QT_API"] = config.get("koapy.qtpy.qt_api", "pyside2") + +# Import proper Qt binding using qtpy +from qtpy import * +from qtpy import PYQT5, PYSIDE2, PythonQtError + +# Check Qt backend +if PYQT5: + if debug: + logger.debug("Using PyQt5 as Qt backend") +elif PYSIDE2: + if debug: + logger.debug("Using PySide2 as Qt backend") +else: + raise PythonQtError("No Qt bindings could be found") + +# PySide2 patch +if PYSIDE2: + import PySide2 + + if hasattr(PySide2, "__file__"): +
[docs] QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join( + os.path.dirname(PySide2.__file__), "plugins", "platforms" + )
+ os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/compat/pywinauto/importlib.html b/_modules/koapy/compat/pywinauto/importlib.html new file mode 100644 index 00000000..06472ee0 --- /dev/null +++ b/_modules/koapy/compat/pywinauto/importlib.html @@ -0,0 +1,200 @@ + + + + + + + + koapy.compat.pywinauto.importlib — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.compat.pywinauto.importlib

+import importlib
+import sys
+import warnings
+
+from importlib.abc import Loader, MetaPathFinder
+
+import pythoncom
+
+
+
[docs]class PyWinAutoFinder(MetaPathFinder): +
[docs] def find_spec(self, fullname, path, target=None): + if fullname == "pywinauto": + self.unregister() + spec = importlib.util.find_spec(fullname) + spec.loader = PyWinAutoLoader() + return spec
+ + @classmethod +
[docs] def register(cls): + sys.meta_path = [cls()] + sys.meta_path
+ + @classmethod +
[docs] def unregister(cls): + sys.meta_path = [x for x in sys.meta_path if not isinstance(x, cls)]
+ + +
[docs]class PyWinAutoLoader(Loader): + def __init__(self): + self._original_coinit_flags_defined = False + self._original_coinit_flags = None + +
[docs] def set_sys_coinit_flags(self): + self._original_coinit_flags_defined = hasattr(sys, "coinit_flags") + self._original_coinit_flags = getattr(sys, "coinit_flags", None) + sys.coinit_flags = pythoncom.COINIT_APARTMENTTHREADED
+ +
[docs] def reset_sys_coinit_flags(self): + if not self._original_coinit_flags_defined: + del sys.coinit_flags + else: + sys.coinit_flags = self._original_coinit_flags
+ +
[docs] def create_module(self, spec): + # set sys.coinit_flags = 2 + # check https://github.com/pywinauto/pywinauto/issues/472 for more information + self.set_sys_coinit_flags() + + # ensure that qt binding is imported before pywinauto import + from koapy.compat import pyside2 + + # import pywinauto + with warnings.catch_warnings(): + warnings.simplefilter("ignore", UserWarning) + module = importlib.import_module(spec.name) + return module
+ +
[docs] def exec_module(self, module): + pass
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/config.html b/_modules/koapy/config.html new file mode 100644 index 00000000..23f8f802 --- /dev/null +++ b/_modules/koapy/config.html @@ -0,0 +1,452 @@ + + + + + + + + koapy.config — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.config

+import subprocess
+import sys
+
+from os import PathLike
+from pathlib import Path
+from typing import Any, Mapping, Optional, Union
+
+from pyhocon import ConfigFactory
+from pyhocon.config_tree import ConfigTree
+from pyhocon.converter import HOCONConverter
+
+from koapy.utils.platform import is_32bit, is_64bit
+
+# Type alias for config object
+
[docs]Config = ConfigTree
+ + +# Paths related to default config file +# bundled with this package for fallback +
[docs]default_config_filename = "config.conf"
+
[docs]default_config_file_directory = Path(__file__).parent
+
[docs]default_config_filepath = default_config_file_directory / default_config_filename
+ + +# Paths related to user config file +# for use customization +
[docs]current_working_directory = Path.cwd()
+
[docs]home_directory = Path.home()
+ +
[docs]default_user_config_filename = "koapy.conf"
+ +
[docs]user_config_filename_cadidates = [ + default_user_config_filename, + "." + default_user_config_filename, +]
+ +
[docs]default_user_config_filepath = home_directory / default_user_config_filename
+ + +# Default encoding for all file read/writes across this package +
[docs]default_encoding = "utf-8"
+ + +# Function for reading configs +
[docs]def read_config( + filename: Optional[Union[PathLike, str]] = None, + encoding: Optional[str] = None, +) -> Config: + if filename is None: + filename = default_user_config_filepath + if isinstance(filename, str): + filename = Path(filename) + if encoding is None: + encoding = default_encoding + # pylint: disable=redefined-outer-name + config = ConfigFactory.parse_file(filename, encoding=encoding) + return config
+ + +# Function for create configs from dict +
[docs]def config_from_dict(dictionary: Mapping[str, Any]) -> Config: + # pylint: disable=redefined-outer-name + config = ConfigFactory.from_dict(dictionary) + return config
+ + +# Load default config bundled with this package for fallback +
[docs]default_config = read_config(default_config_filepath)
+ + +# Try to read user config file from candidate paths +# 1. Starting from current directory, search for a user config file until reaching the root directory, with specific name patterns +# 2. In terms of user config filename pattern, visible filename takes precedence to hidden filename (hidden that starts with a dot) +# 3. If fails to find a user config file even in the root directory, finally check user home directory for a user config file + + +# Search for a user config file in a given directory +
[docs]def find_user_config_file_in( + searching_directory: Optional[Union[PathLike, str]] = None, +) -> Optional[Path]: + if searching_directory is None: + # pylint: disable=redefined-outer-name + current_working_directory = Path.cwd() + searching_directory = current_working_directory + searching_directory_path = Path(searching_directory).resolve() + for config_filename in user_config_filename_cadidates: + config_filepath = searching_directory_path / config_filename + if config_filepath.exists(): + return config_filepath
+ + +# Search for a user config file from a given directory to the root directory +
[docs]def find_user_config_file_from( + starting_directory: Optional[Union[PathLike, str]] = None, +) -> Optional[Path]: + if starting_directory is None: + # pylint: disable=redefined-outer-name + current_working_directory = Path.cwd() + starting_directory = current_working_directory + searching_directory_path = Path(starting_directory).resolve() + should_stop = False + while not should_stop: + config_filepath = find_user_config_file_in(searching_directory_path) + if config_filepath: + return config_filepath + has_no_more_parent = ( + str(searching_directory_path) == searching_directory_path.anchor + ) + should_stop = has_no_more_parent + searching_directory_path = searching_directory_path.parent
+ + +# Empty config for internal usage +
[docs]empty_config = config_from_dict({})
+ +# Prepare user config before reading actual user config file (which may not exist) +
[docs]user_config = empty_config
+ +# Main config object for general use +# User config takes precedence and fallbacks to default config for missing entries +
[docs]config = user_config.with_fallback(default_config)
+ + +# Helper function for updating `user_config`, mostly for internal use +# This also consequently updates `config` global variable +
[docs]def set_user_config(c: Config) -> Config: + global user_config # pylint: disable=global-statement + global config # pylint: disable=global-statement + user_config = c + config = user_config.with_fallback(default_config) + return user_config
+ + +# Function for config initialization +
[docs]def initialize_config_from_given_path( + filename: Optional[Union[PathLike, str]] = None +) -> bool: + user_config_filepath: Optional[PathLike] = None + initialized = False + + # Use given filepath if possible + if not user_config_filepath: + if filename: + filepath = Path(filename).resolve() + if filepath.exists(): + user_config_filepath = filepath + + if user_config_filepath: + # pylint: disable=redefined-outer-name + user_config = read_config(user_config_filepath) + set_user_config(user_config) + initialized = True + + return initialized
+ + +# Function for config initialization +
[docs]def initialize_config_from_expected_paths() -> bool: + user_config_filepath: Optional[PathLike] = None + initialized = False + + # Try searching starting from current directory to root + if not user_config_filepath: + user_config_filepath = find_user_config_file_from(current_working_directory) + + # Try searching in home directory + if not user_config_filepath: + user_config_filepath = find_user_config_file_in(home_directory) + + # If user config file is found, read the config file + # This overwrites previously declared emtpy `user_config` global variable + if user_config_filepath: + # pylint: disable=redefined-outer-name + user_config = read_config(user_config_filepath) + set_user_config(user_config) + initialized = True + + return initialized
+ + +# Just run basic initializtion for the first time +initialize_config_from_expected_paths() + + +# Simple helper function for getting config +
[docs]def get_config() -> Config: + return config
+ + +# Simple helper function for getting user config +
[docs]def get_user_config() -> Config: + return user_config
+ + +# Flag value for additional logging for debugging purpose (mainly in development process) +
[docs]debug = False
+ + +# Dump config object to string +
[docs]def dump_config( + config: Config, + compact: bool = False, + indent: int = 4, +) -> str: + # pylint: disable=redefined-outer-name + hocon = HOCONConverter.to_hocon(config, compact=compact, indent=indent) + return hocon
+ + +# Save config to file +
[docs]def save_config( + filename: Union[PathLike, str], + config: Optional[Config] = None, + compact: bool = False, + indent: int = 4, + encoding: Optional[str] = None, +): + # pylint: disable=redefined-outer-name + if config is None: + config = get_config() + if encoding is None: + encoding = default_encoding + hocon = dump_config(config, compact=compact, indent=indent) + with open(filename, "w", encoding=encoding) as f: + f.write(hocon)
+ + +# Save user config to file (without default fallbacks) +
[docs]def save_user_config( + filename: Optional[Union[PathLike, str]] = None, + user_config: Optional[Config] = None, + compact: bool = False, + indent: int = 4, + encoding: Optional[str] = None, +): + # pylint: disable=redefined-outer-name + if filename is None: + filename = default_user_config_filepath + if user_config is None: + user_config = get_user_config() + if encoding is None: + encoding = default_encoding + save_config(filename, user_config, compact, indent, encoding)
+ + +# Helper functions for getting python executables below +
[docs]def get_executable_from_conda_envname(envname: str) -> str: + return subprocess.check_output( + [ + "conda", + "run", + "-n", + envname, + "python", + "-c", + "import sys; print(sys.executable)", + ], + encoding=sys.stdout.encoding, + creationflags=subprocess.CREATE_NO_WINDOW, + ).strip()
+ + +
[docs]def get_executable_from_conda_envpath(envpath: str) -> str: + return subprocess.check_output( + [ + "conda", + "run", + "-p", + envpath, + "python", + "-c", + "import sys; print(sys.executable)", + ], + encoding=sys.stdout.encoding, + creationflags=subprocess.CREATE_NO_WINDOW, + ).strip()
+ + +
[docs]def get_executable_from_executable_config(executable_config: Config) -> Optional[str]: + if isinstance(executable_config, str): + return executable_config + if isinstance(executable_config, dict): + if "path" in executable_config: + return executable_config["path"] + if "conda" in executable_config: + conda_config = executable_config["conda"] + if isinstance(conda_config, str): + envname = conda_config + return get_executable_from_conda_envname(envname) + if isinstance(conda_config, dict): + if "name" in conda_config: + envname = conda_config["name"] + return get_executable_from_conda_envname(envname) + if "path" in conda_config: + envpath = conda_config["path"] + return get_executable_from_conda_envpath(envpath)
+ + +
[docs]def get_32bit_executable() -> Optional[str]: + if is_32bit(): + return sys.executable + executable_config = config.get("koapy.python.executable.32bit") + return get_executable_from_executable_config(executable_config)
+ + +
[docs]def get_64bit_executable() -> Optional[str]: + if is_64bit(): + return sys.executable + executable_config = config.get("koapy.python.executable.64bit") + return get_executable_from_executable_config(executable_config)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/builtin.html b/_modules/koapy/utils/builtin.html new file mode 100644 index 00000000..452c034f --- /dev/null +++ b/_modules/koapy/utils/builtin.html @@ -0,0 +1,144 @@ + + + + + + + + koapy.utils.builtin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.builtin

+
[docs]def dir_public(*args): + return [name for name in dir(*args) if not name.startswith("_")]
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/ctypes.html b/_modules/koapy/utils/ctypes.html new file mode 100644 index 00000000..e4619e5f --- /dev/null +++ b/_modules/koapy/utils/ctypes.html @@ -0,0 +1,147 @@ + + + + + + + + koapy.utils.ctypes — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.ctypes

+import ctypes
+
+
+
[docs]def is_admin(): + return ctypes.windll.shell32.IsUserAnAdmin() != 0
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.html b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.html new file mode 100644 index 00000000..9864e2d8 --- /dev/null +++ b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.html @@ -0,0 +1,304 @@ + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.data.KrxHistoricalDailyPriceDataDownloader

+import pandas as pd
+import requests
+
+from exchange_calendars import get_calendar
+
+
+
[docs]class KrxHistoricalDailyPriceDataDownloader: + def __init__(self): + self._headers = { + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "en-US,en;q=0.9,ko;q=0.8,fr;q=0.7,ja;q=0.6,zh-CN;q=0.5,zh;q=0.4", + "Host": "data.krx.co.kr", + "Origin": "http://data.krx.co.kr", + "Referer": "http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201020103", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", + "X-Requested-With": "XMLHttpRequest", + } + + self._stocks = None + self._stocks_delisted = None + + self._bld = "dbms/MDC/STAT/standard/MDCSTAT01701" + self._isuCd = "" + + self._calendar = get_calendar("XKRX") + self._start_date = self._calendar.first_session.astimezone( + self._calendar.tz + ).normalize() + +
[docs] def get_stocks(self): + data = { + "mktsel": "ALL", + "typeNo": "0", + "searchText": "", + "bld": "dbms/comm/finder/finder_stkisu", + } + url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" + response = requests.post(url, data, headers=self._headers) + df = pd.json_normalize(response.json()["block1"]) + df = df.set_index("short_code") + return df
+ +
[docs] def get_stocks_delisted(self): + data = { + "mktsel": "ALL", + "searchText": "", + "bld": "dbms/comm/finder/finder_listdelisu", + } + url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" + response = requests.post(url, data, headers=self._headers) + df = pd.json_normalize(response.json()["block1"]) + df = df.set_index("short_code") + return df
+ + @property +
[docs] def stocks(self): + if self._stocks is None: + self._stocks = self.get_stocks() + return self._stocks
+ + @property +
[docs] def stocks_delisted(self): + if self._stocks_delisted is None: + self._stocks_delisted = self.get_stocks_delisted() + return self._stocks_delisted
+ +
[docs] def get_full_code(self, symbol): + if symbol in self.stocks.index: + return self.stocks.loc[symbol]["full_code"] + if symbol in self.stocks_delisted.index: + return self.stocks_delisted.loc[symbol]["full_code"] + raise ValueError("No full_code found for given symbol %s" % symbol)
+ +
[docs] def get_name(self, symbol): + if symbol in self.stocks.index: + return self.stocks.loc[symbol]["codeName"] + if symbol in self.stocks_delisted.index: + return self.stocks_delisted.loc[symbol]["codeName"] + raise ValueError("No name found for given symbol %s" % symbol)
+ +
[docs] def download(self, symbol, start_date=None, end_date=None): + if start_date is None: + start_date = self._start_date + if end_date is None: + now = pd.Timestamp.now(self._calendar.tz) + end_date = ( + self._calendar.previous_close(now) + .astimezone(self._calendar.tz) + .normalize() + ) + + full_code = self.get_full_code(symbol) + name = self.get_name(symbol) + + url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" + data = { + "bld": self._bld, + "tboxisuCd_finder_stkisu0_0": "{}/{}".format(symbol, name), + "isuCd": full_code, + "isuCd2": self._isuCd, + "codeNmisuCd_finder_stkisu0_0": name, + "param1isuCd_finder_stkisu0_0": "ALL", + "strtDd": start_date.strftime("%Y%m%d"), + "endDd": end_date.strftime("%Y%m%d"), + "share": "1", + "money": "1", + "csvxls_isNo": "false", + } + self._isuCd = full_code + + response = requests.post(url, data, headers=self._headers) + output = response.json()["output"] + + if len(output) == 0: + return None + + df = pd.json_normalize(output) + + column_names = { + "TRD_DD": "Date", + "ISU_CD": "Code", + "ISU_NM": "Name", + "MKT_NM": "Market", + "SECUGRP_NM": "SecuGroup", + "TDD_CLSPRC": "Close", + "FLUC_TP_CD": "UpDown", + "CMPPRVDD_PRC": "Change", + "FLUC_RT": "ChangeRate", + "TDD_OPNPRC": "Open", + "TDD_HGPRC": "High", + "TDD_LWPRC": "Low", + "ACC_TRDVOL": "Volume", + "ACC_TRDVAL": "Amount", + "MKTCAP": "MarCap", + "CMPPREVDD_PRC": "Change", + "LIST_SHRS": "Shares", + } + df.rename(columns=column_names, inplace=True) + + int_columns = [ + "Close", + "UpDown", + "Change", + "ChangeRate", + "Open", + "High", + "Low", + "Volume", + "Amount", + "MarCap", + "Shares", + ] + + for col in int_columns: + if col in df.columns: + df[col] = pd.to_numeric(df[col].str.replace(",", ""), errors="coerce") + + df["Date"] = pd.to_datetime(df["Date"]) + df.set_index("Date", inplace=True) + + return df
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.html b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.html new file mode 100644 index 00000000..9d872035 --- /dev/null +++ b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.html @@ -0,0 +1,277 @@ + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader

+import numpy as np
+import pandas as pd
+
+from exchange_calendars import get_calendar
+from tqdm import tqdm
+
+from ..store import SQLiteStore
+from .KrxHistoricalDailyPriceDataLoader import KrxHistoricalDailyPriceDataLoader
+
+
+
[docs]class KrxHistoricalDailyPriceDataForBacktestLoader: + def __init__(self, filename, library=None): + self._loader = KrxHistoricalDailyPriceDataLoader(filename) + self._store = SQLiteStore(filename) + self._calendar = get_calendar("XKRX") + + if library is None: + library = "XKRX-ALL-BACKTEST" + + self._library = self._store.get_or_create_library(library) + + @classmethod +
[docs] def get_adjust_ratios(cls, data, sort=True): + if sort: + data = data.sort_index(ascending=False) + adjust_ratios = [] + last_close = data["Close"].iloc[0] + last_adjust_ratio = 1.0 + adjust_ratios.append(last_adjust_ratio) + eleven_days = pd.Timedelta(11, unit="D") + for i in range(data.shape[0] - 1): + if data.index[i] - data.index[i + 1] > eleven_days: + last_close = data["Close"].iloc[i + 1] + last_adjust_ratio = 1.0 + else: + last_close = last_close - data["Change"].iloc[i] * last_adjust_ratio + last_adjust_ratio = last_close / data["Close"].iloc[i + 1] + adjust_ratios.append(last_adjust_ratio) + adjust_ratios = np.array(adjust_ratios) + return adjust_ratios
+ + @classmethod +
[docs] def adjust_data(cls, data, sort=True): + if sort: + data = data.sort_index(ascending=False) + adjust_ratios = cls.get_adjust_ratios(data, sort=False) + data["Open"] = data["Open"] * adjust_ratios + data["High"] = data["High"] * adjust_ratios + data["Low"] = data["Low"] * adjust_ratios + data["Close"] = data["Close"] * adjust_ratios + data["Volume"] = data["Volume"] / adjust_ratios + return data
+ +
[docs] def get_symbols(self): + return self._library.list_symbols()
+ +
[docs] def update(self, download=False, progress_bar=False): + now = pd.Timestamp.now(self._calendar.tz) + end_date = ( + self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize() + ) + + symbols_with_delisted = {} + + for symbol in self._loader.symbols: + symbols_with_delisted.setdefault(symbol, False) + for symbol in self._loader.symbols_delisted: + symbols_with_delisted.setdefault(symbol, True) + + entire_index = pd.DatetimeIndex([], name="Date") + + entire_data = {} + entire_data_converted = {} + + progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar) + for symbol, is_delisted in progress: + progress.set_description("Loading Symbol [%s]" % symbol) + if download: + versioned_item = self._loader.load_or_download( + symbol, is_delisted=is_delisted, end_date=end_date + ) + else: + versioned_item = self._loader.load_from_database( + symbol, is_delisted=is_delisted + ) + if versioned_item is not None: + entire_data[symbol] = versioned_item.data + + progress = tqdm(entire_data.items(), disable=not progress_bar) + for symbol, data in progress: + progress.set_description("Adjusting Symbol [%s]" % symbol) + entire_index = entire_index.union(data.index) + data = data[data["Close"] > 0] + if data.shape[0] > 0: + data = self.adjust_data(data) + data = data.sort_index() + columns = [ + "Open", + "High", + "Low", + "Close", + "Volume", + "Amount", + "MarCap", + "Shares", + ] + data = data[columns] + entire_data_converted[symbol] = data + + progress = tqdm(entire_data_converted.items(), disable=not progress_bar) + for symbol, data in progress: + progress.set_description("Saving Symbol [%s]" % symbol) + data = data.reindex(entire_index) + data = data.fillna(0) + self._library.write(symbol, data)
+ +
[docs] def load(self, symbol, start_time=None, end_time=None): + if self._library.has_symbol(symbol): + versioned_item = self._library.read( + symbol, start_time=start_time, end_time=end_time + ) + if ( + versioned_item is not None + and versioned_item.data is not None + and versioned_item.data.shape[0] > 0 + ): + return versioned_item.data
+ +
[docs] def load_as_cursor(self, symbol, start_time=None, end_time=None): + if self._library.has_symbol(symbol): + versioned_item = self._library.read_as_cursor( + symbol, start_time=start_time, end_time=end_time + ) + if versioned_item is not None and versioned_item.data is not None: + return versioned_item.data
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.html b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.html new file mode 100644 index 00000000..b52bca85 --- /dev/null +++ b/_modules/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.html @@ -0,0 +1,263 @@ + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataLoader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.data.KrxHistoricalDailyPriceDataLoader

+import pandas as pd
+
+from exchange_calendars import get_calendar
+from tqdm import tqdm
+
+from ..store import SQLiteStore
+from .KrxHistoricalDailyPriceDataDownloader import KrxHistoricalDailyPriceDataDownloader
+
+
+
[docs]class KrxHistoricalDailyPriceDataLoader: + def __init__(self, filename, library=None, library_delisted=None): + self._downloader = KrxHistoricalDailyPriceDataDownloader() + self._store = SQLiteStore(filename) + self._calendar = get_calendar("XKRX") + + if library is None: + library = "XKRX" + if library_delisted is None: + library_delisted = "XKRX-DELISTED" + + self._library = self._store.get_or_create_library(library) + self._library_delisted = self._store.get_or_create_library(library_delisted) + + @property +
[docs] def symbols(self): + return self._downloader.stocks.index
+ + @property +
[docs] def symbols_delisted(self): + return self._downloader.stocks_delisted.index
+ +
[docs] def load_from_database(self, symbol, is_delisted=None): + if is_delisted is None: + is_delisted = symbol not in self.symbols + + library = self._library if not is_delisted else self._library_delisted + + if library.has_symbol(symbol): + versioned_item = library.read(symbol) + if versioned_item.data is not None and versioned_item.data.shape[0] > 0: + return versioned_item
+ +
[docs] def load_or_download( + self, symbol, is_delisted=None, start_date=None, end_date=None + ): + if is_delisted is None: + is_delisted = symbol not in self.symbols + + library = self._library + now = pd.Timestamp.now(self._calendar.tz) + + if is_delisted: + library = self._library_delisted + + if library.has_symbol(symbol): + versioned_item = self.load_from_database(symbol, is_delisted=is_delisted) + if not is_delisted and versioned_item is not None: + if start_date is None: + start_date = ( + versioned_item.data.index.max().tz_localize(self._calendar.tz) + + self._calendar.day + ) + if end_date is None: + end_date = ( + self._calendar.previous_close(now) + .astimezone(self._calendar.tz) + .normalize() + ) + if start_date <= end_date: + recent_data = self._downloader.download( + symbol, start_date=start_date + ) + if recent_data is not None and recent_data.shape[0] > 0: + data = versioned_item.data + data = data.combine_first(recent_data)[data.columns] + data = data.convert_dtypes(convert_floating=False) + data = data.sort_index() + versioned_item = library.write(symbol, data) + return versioned_item + else: + data = self._downloader.download( + symbol, start_date=start_date, end_date=end_date + ) + if data is not None and data.shape[0] > 0: + data = data.convert_dtypes(convert_floating=False) + data = data.sort_index() + versioned_item = library.write(symbol, data) + return versioned_item
+ +
[docs] def load( + self, symbol, is_delisted=None, start_date=None, end_date=None, download=True + ): + if download: + return self.load_or_download( + symbol, + is_delisted=is_delisted, + start_date=start_date, + end_date=end_date, + ) + else: + return self.load_from_database(symbol, is_delisted=is_delisted)
+ +
[docs] def update(self, progress_bar=False): + now = pd.Timestamp.now(self._calendar.tz) + end_date = ( + self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize() + ) + + symbols_with_delisted = {} + + for symbol in self.symbols: + symbols_with_delisted.setdefault(symbol, False) + for symbol in self.symbols_delisted: + symbols_with_delisted.setdefault(symbol, True) + + progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar) + for symbol, is_delisted in progress: + progress.set_description("Updating Symbol [%s]" % symbol) + _versioned_item = self.load_or_download( + symbol, is_delisted=is_delisted, end_date=end_date + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.html b/_modules/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.html new file mode 100644 index 00000000..17f38c0f --- /dev/null +++ b/_modules/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.html @@ -0,0 +1,181 @@ + + + + + + + + koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader

+import io
+
+import pandas as pd
+import requests
+
+
+
[docs]class YahooFinanceKrxHistoricalDailyPriceDataDownloader: + def __init__(self): + self._headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36", + } + +
[docs] def download(self, symbol, start_date=None, end_date=None): + if start_date is None: + start_date = pd.Timestamp(1980, 1, 1) + elif not isinstance(start_date, pd.Timestamp): + start_date = pd.Timestamp(start_date) + if end_date is None: + end_date = pd.Timestamp.now().normalize() + pd.Timedelta(1, unit="day") + elif not isinstance(end_date, pd.Timestamp): + end_date = pd.Timestamp(end_date) + + url = ( + "https://query1.finance.yahoo.com/v7/finance/download/%s.KS" + % symbol.upper() + ) + params = { + "period1": int(start_date.timestamp()), + "period2": int(end_date.timestamp()), + "interval": "1d", + "events": "history", + "includeAdjustedClose": "true", + } + response = requests.get(url, params=params, headers=self._headers) + df = pd.read_csv( + io.BytesIO(response.content), parse_dates=["Date"], index_col="Date" + ) + + return df
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/datetime.html b/_modules/koapy/utils/datetime.html new file mode 100644 index 00000000..c864bbd1 --- /dev/null +++ b/_modules/koapy/utils/datetime.html @@ -0,0 +1,152 @@ + + + + + + + + koapy.utils.datetime — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.datetime

+
[docs]def is_naive(dt): + return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None
+ + +
[docs]def localize(dt, tz): + if is_naive(dt): + dt = tz.localize(dt) + else: + dt = dt.astimezone(tz) + return dt
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/exchange_calendars.html b/_modules/koapy/utils/exchange_calendars.html new file mode 100644 index 00000000..edc8b7a0 --- /dev/null +++ b/_modules/koapy/utils/exchange_calendars.html @@ -0,0 +1,162 @@ + + + + + + + + koapy.utils.exchange_calendars — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.exchange_calendars

+from exchange_calendars import get_calendar
+from pandas import Timestamp
+
+
[docs]name = "XKRX"
+
[docs]calendar = get_calendar(name)
+
[docs]day = calendar.day
+ + +
[docs]def is_currently_in_session() -> bool: + now = Timestamp.now(calendar.tz).floor("T") + previous_open = calendar.previous_open(now).astimezone(calendar.tz) + next_close = calendar.next_close(previous_open).astimezone(calendar.tz) + return previous_open <= now <= next_close
+ + +
[docs]def get_last_session_date() -> Timestamp: + now = Timestamp.now(calendar.tz).floor("T") + previous_close = calendar.previous_close(now).astimezone(calendar.tz) + previous_open = calendar.previous_open(previous_close).astimezone(calendar.tz) + return previous_open.normalize()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/grpc.html b/_modules/koapy/utils/grpc.html new file mode 100644 index 00000000..b09b25e6 --- /dev/null +++ b/_modules/koapy/utils/grpc.html @@ -0,0 +1,176 @@ + + + + + + + + koapy.utils.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.grpc

+import contextlib
+import threading
+import warnings
+
+from pprint import PrettyPrinter
+
+import grpc
+
+from google.protobuf.json_format import MessageToDict
+
+
+@contextlib.contextmanager
+
[docs]def warn_on_rpc_error_context(): + try: + yield + except grpc.RpcError as e: + warnings.warn(str(e))
+ + +
[docs]def warn_on_rpc_error(stream): + with warn_on_rpc_error_context(): + for event in stream: + yield event
+ + +
[docs]def cancel_after(stream, after): + timer = threading.Timer(after, stream.cancel) + timer.start() + return warn_on_rpc_error(stream)
+ + +
[docs]def pprint_message(message): + pp = PrettyPrinter() + pp.pprint(MessageToDict(message, preserving_proto_field_name=True))
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/itertools.html b/_modules/koapy/utils/itertools.html new file mode 100644 index 00000000..d1e68cc6 --- /dev/null +++ b/_modules/koapy/utils/itertools.html @@ -0,0 +1,151 @@ + + + + + + + + koapy.utils.itertools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.itertools

+import itertools
+
+
+
[docs]def chunk(iterable, n): + fillvalue = object() + args = [iter(iterable)] * n + it = itertools.zip_longest(fillvalue=fillvalue, *args) + it = map(lambda items: [item for item in items if item is not fillvalue], it) + return it
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging.html b/_modules/koapy/utils/logging.html new file mode 100644 index 00000000..90daae97 --- /dev/null +++ b/_modules/koapy/utils/logging.html @@ -0,0 +1,183 @@ + + + + + + + + koapy.utils.logging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging

+from .Logging import Logging
+
+
+
[docs]def get_logger(name=None): + return Logging.get_logger(name)
+ + +
[docs]def verbosity_to_loglevel(verbosity): + return Logging.verbosity_to_loglevel(verbosity)
+ + +
[docs]def loglevel_to_verbosity(loglevel): + return Logging.loglevel_to_verbosity(loglevel)
+ + +
[docs]def get_package_logger(): + root_package_name = __name__.split(".", maxsplit=1)[0] + logger = get_logger(root_package_name) + return logger
+ + +
[docs]def set_loglevel(loglevel): + logger = get_package_logger() + logger.setLevel(loglevel)
+ + +
[docs]def set_verbosity(verbosity): + loglevel = verbosity_to_loglevel(verbosity) + set_loglevel(loglevel)
+ + +
[docs]def get_loglevel(): + logger = get_package_logger() + loglevel = logger.level + return loglevel
+ + +
[docs]def get_verbosity(): + loglevel = get_loglevel() + verbosity = loglevel_to_verbosity(loglevel) + return verbosity
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/Logging.html b/_modules/koapy/utils/logging/Logging.html new file mode 100644 index 00000000..e9be42e0 --- /dev/null +++ b/_modules/koapy/utils/logging/Logging.html @@ -0,0 +1,295 @@ + + + + + + + + koapy.utils.logging.Logging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.Logging

+import inspect
+import logging
+import logging.config
+import threading
+
+
+
[docs]class LoggingMeta(type): + + __default_config = { + "version": 1, + "formatters": { + "default": { + "format": "%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", + }, + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "level": "NOTSET", + "formatter": "default", + }, + }, + "loggers": { + "koapy": { + "level": "DEBUG", + "propagate": False, + "handlers": ["console"], + }, + }, + "incremental": False, + "disable_existing_loggers": False, + } + + __config_key = "koapy.utils.logging.config" + + __initialized = False + __init_lock = threading.RLock() + + def __initialize_if_necessary(cls): + if not LoggingMeta.__initialized: + with LoggingMeta.__init_lock: + if not LoggingMeta.__initialized: + LoggingMeta.__initialize(cls) + + def __initialize(cls): + from koapy.config import config + + logging_config_dict = config.get( + LoggingMeta.__config_key, LoggingMeta.__default_config + ) + + logging.basicConfig() + logging.config.dictConfig(logging_config_dict) + LoggingMeta.__initialized = True + + def __new__(cls, clsname, bases, dct): + return super().__new__(cls, clsname, bases, dct) + + def __init__(cls, clsname, bases, dct): + super().__init__(clsname, bases, dct) + cls.__logger = None + +
[docs] def get_logger(cls, name=None): + LoggingMeta.__initialize_if_necessary(cls) + logger = logging.getLogger(name) + return logger
+ + def __module_name(cls): + module = inspect.getmodule(cls) + module_name = module.__spec__ and module.__spec__.name or module.__name__ + return module_name + + def __class_name(cls): + class_name = cls.__name__ + if hasattr(cls, "__outer_class__"): + class_name = "{}.{}".format( + LoggingMeta.__class_name(cls.__outer_class__), + class_name, + ) + return class_name + + def __logger_name(cls): + module_name = LoggingMeta.__module_name(cls) + class_name = LoggingMeta.__class_name(cls) + logger_name = "{}.{}".format(module_name, class_name) + return logger_name + +
[docs] def get_class_logger(cls): + name = LoggingMeta.__logger_name(cls) + logger = LoggingMeta.get_logger(cls, name) + return logger
+ +
[docs] def get_module_logger(cls): + name = LoggingMeta.__module_name(cls) + logger = LoggingMeta.get_logger(cls, name) + return logger
+ +
[docs] def get_package_logger(cls): + name = LoggingMeta.__module_name(cls) + name = name.split(".", maxsplit=1)[0] + logger = LoggingMeta.get_logger(cls, name) + return logger
+ + def _logger(cls): + if cls.__logger is None: + cls.__logger = LoggingMeta.get_class_logger(cls) + return cls.__logger + + @property +
[docs] def logger(cls): + return LoggingMeta._logger(cls)
+ +
[docs] def verbosity_to_loglevel(cls, verbosity): + verbosity = verbosity or 0 + levels = [ + logging.WARNING, + logging.INFO, + logging.DEBUG, + ] + if verbosity >= len(levels): + verbosity = -1 + level = levels[verbosity] + return level
+ +
[docs] def loglevel_to_verbosity(cls, loglevel): + verbosity = 3 - (loglevel + 9) // 10 + if verbosity < 0: + verbosity = 0 + return verbosity
+ +
[docs] def set_loglevel(cls, loglevel=logging.WARNING): + return LoggingMeta._logger(cls).setLevel(loglevel)
+ +
[docs] def set_verbosity(cls, verbosity=0): + loglevel = LoggingMeta.verbosity_to_loglevel(cls, verbosity) + LoggingMeta.set_loglevel(cls, loglevel) + return loglevel
+ +
[docs] def get_loglevel(cls): + return LoggingMeta._logger(cls).level
+ +
[docs] def get_verbosity(cls): + loglevel = LoggingMeta.get_loglevel(cls) + verbosity = LoggingMeta.loglevel_to_verbosity(cls, loglevel) + return verbosity
+ + +
[docs]class Logging(metaclass=LoggingMeta): + @property +
[docs] def logger(self): + return type(self)._logger()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/pyside2/QAbstractSocketLogging.html b/_modules/koapy/utils/logging/pyside2/QAbstractSocketLogging.html new file mode 100644 index 00000000..2c149b8c --- /dev/null +++ b/_modules/koapy/utils/logging/pyside2/QAbstractSocketLogging.html @@ -0,0 +1,158 @@ + + + + + + + + koapy.utils.logging.pyside2.QAbstractSocketLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.pyside2.QAbstractSocketLogging

+from koapy.compat.pyside2.QtNetwork import QAbstractSocket
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class QAbstractSocketLoggingMeta(type(Logging), type(QAbstractSocket)): + pass
+ + +
[docs]class QAbstractSocketLogging( + QAbstractSocket, Logging, metaclass=QAbstractSocketLoggingMeta +): + def __init__(self, *args, **kwargs): + QAbstractSocket.__init__(self, *args, **kwargs) + Logging.__init__(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/pyside2/QObjectLogging.html b/_modules/koapy/utils/logging/pyside2/QObjectLogging.html new file mode 100644 index 00000000..a2e3613a --- /dev/null +++ b/_modules/koapy/utils/logging/pyside2/QObjectLogging.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.utils.logging.pyside2.QObjectLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.pyside2.QObjectLogging

+from koapy.compat.pyside2.QtCore import QObject
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class QObjectLoggingMeta(type(Logging), type(QObject)): + pass
+ + +
[docs]class QObjectLogging(QObject, Logging, metaclass=QObjectLoggingMeta): + def __init__(self, *args, **kwargs): + QObject.__init__(self, *args, **kwargs) + Logging.__init__(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/pyside2/QThreadLogging.html b/_modules/koapy/utils/logging/pyside2/QThreadLogging.html new file mode 100644 index 00000000..5eb72106 --- /dev/null +++ b/_modules/koapy/utils/logging/pyside2/QThreadLogging.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.utils.logging.pyside2.QThreadLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.pyside2.QThreadLogging

+from koapy.compat.pyside2.QtCore import QThread
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class QThreadLoggingMeta(type(Logging), type(QThread)): + pass
+ + +
[docs]class QThreadLogging(QThread, Logging, metaclass=QThreadLoggingMeta): + def __init__(self, *args, **kwargs): + QThread.__init__(self, *args, **kwargs) + Logging.__init__(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/pyside2/QWidgetLogging.html b/_modules/koapy/utils/logging/pyside2/QWidgetLogging.html new file mode 100644 index 00000000..e8ac0baf --- /dev/null +++ b/_modules/koapy/utils/logging/pyside2/QWidgetLogging.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.utils.logging.pyside2.QWidgetLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.pyside2.QWidgetLogging

+from koapy.compat.pyside2.QtWidgets import QWidget
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class QWidgetLoggingMeta(type(Logging), type(QWidget)): + pass
+ + +
[docs]class QWidgetLogging(QWidget, Logging, metaclass=QWidgetLoggingMeta): + def __init__(self, *args, **kwargs): + QWidget.__init__(self, *args, **kwargs) + Logging.__init__(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/logging/tqdm/TqdmStreamHandler.html b/_modules/koapy/utils/logging/tqdm/TqdmStreamHandler.html new file mode 100644 index 00000000..d113a04e --- /dev/null +++ b/_modules/koapy/utils/logging/tqdm/TqdmStreamHandler.html @@ -0,0 +1,157 @@ + + + + + + + + koapy.utils.logging.tqdm.TqdmStreamHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.logging.tqdm.TqdmStreamHandler

+import sys
+
+from logging import StreamHandler
+
+from tqdm.contrib import DummyTqdmFile
+
+
+
[docs]class TqdmStreamHandler(StreamHandler): + def __init__(self, stream=None): + if stream is None: + stream = sys.stderr + stream = DummyTqdmFile(stream) + StreamHandler.__init__(self, stream)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/messaging/DiscordMessenger.html b/_modules/koapy/utils/messaging/DiscordMessenger.html new file mode 100644 index 00000000..8c233ea0 --- /dev/null +++ b/_modules/koapy/utils/messaging/DiscordMessenger.html @@ -0,0 +1,183 @@ + + + + + + + + koapy.utils.messaging.DiscordMessenger — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.messaging.DiscordMessenger

+import json
+
+import requests
+
+from discord import RequestsWebhookAdapter, Webhook
+
+from koapy.config import config
+from koapy.utils.messaging.Messenger import Messenger
+
+
+
[docs]class DiscordWebhookMessenger(Messenger): + def __init__(self, url=None): + self._url = url or config.get_string( + "koapy.utils.messaging.discord.webhook_url" + ) + assert self._url is not None and len(self._url) > 0 + self._webhook = Webhook.from_url(self._url, adapter=RequestsWebhookAdapter()) + +
[docs] def send_message(self, content): + return self._webhook.send(content)
+ + +
[docs]class DoItYourselfDiscordWebhookMessenger(Messenger): + def __init__(self, url=None): + self._url = url or config.get_string( + "koapy.utils.messaging.discord.webhook_url" + ) + assert self._url is not None and len(self._url) > 0 + +
[docs] def send_message(self, content): + headers = { + "Content-Type": "application/json", + } + data = { + "content": content, + } + data = json.dumps(data) + response = requests.post( + self._url, headers=headers, data=data, params={"wait": "true"} + ) + return response
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/messaging/Messenger.html b/_modules/koapy/utils/messaging/Messenger.html new file mode 100644 index 00000000..481aaabd --- /dev/null +++ b/_modules/koapy/utils/messaging/Messenger.html @@ -0,0 +1,151 @@ + + + + + + + + koapy.utils.messaging.Messenger — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.messaging.Messenger

+from abc import ABC, abstractmethod
+
+
+
[docs]class Messenger(ABC): + """ """ + + @abstractmethod +
[docs] def send_message(self, content): + raise NotImplementedError
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/networking.html b/_modules/koapy/utils/networking.html new file mode 100644 index 00000000..df0b8fa4 --- /dev/null +++ b/_modules/koapy/utils/networking.html @@ -0,0 +1,177 @@ + + + + + + + + koapy.utils.networking — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.networking

+import ipaddress
+import socket
+
+from contextlib import closing
+
+from wrapt import synchronized
+
+
+@synchronized
+
[docs]def find_free_port_for_host(host): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + with closing(sock) as sock: + sock.bind((host, 0)) + host, port = sock.getsockname() + return port
+ + +
[docs]def get_free_localhost_port(): + return find_free_port_for_host("localhost")
+ + +
[docs]def is_in_private_network(host): + host = socket.gethostbyname(host) + ip_address = ipaddress.ip_address(host) + private_networks = [ + "10.0.0.0/8", + "127.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + ] + private_networks = [ipaddress.ip_network(network) for network in private_networks] + for private_network in private_networks: + if ip_address in private_network: + return True + return False
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/notimplemented.html b/_modules/koapy/utils/notimplemented.html new file mode 100644 index 00000000..d7d4304e --- /dev/null +++ b/_modules/koapy/utils/notimplemented.html @@ -0,0 +1,153 @@ + + + + + + + + koapy.utils.notimplemented — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.notimplemented

+
[docs]def notimplemented(func): + func.__isnotimplemented__ = True + return func
+ + +
[docs]def isnotimplemented(func): + return getattr(func, "__isnotimplemented__", False)
+ + +
[docs]def isimplemented(func): + return not isnotimplemented(func)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/platform.html b/_modules/koapy/utils/platform.html new file mode 100644 index 00000000..3697a6fa --- /dev/null +++ b/_modules/koapy/utils/platform.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.utils.platform — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.platform

+import platform
+import sys
+
+
+
[docs]def is_windows(): + return sys.platform == "win32"
+ + +
[docs]def is_32bit(): + return platform.architecture()[0] == "32bit"
+ + +
[docs]def is_64bit(): + return platform.architecture()[0] == "64bit"
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/pywin32.html b/_modules/koapy/utils/pywin32.html new file mode 100644 index 00000000..e9e799c0 --- /dev/null +++ b/_modules/koapy/utils/pywin32.html @@ -0,0 +1,290 @@ + + + + + + + + koapy.utils.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.pywin32

+from typing import Dict, List, Optional, Sequence, Tuple, Union
+
+try:
+    from typing import TypeGuard
+except ImportError:
+    from typing_extensions import TypeGuard
+
+import pythoncom
+import win32api
+import win32con
+
+from pywintypes import IIDType
+from win32com.client.genpy import (
+    DispatchItem,
+    EnumerationItem,
+    Generator,
+    RecordItem,
+    VTableItem,
+)
+from win32com.client.selecttlb import EnumKeys, TypelibSpec
+
+
[docs]PyIID = IIDType
+
[docs]PyITypeLib = "PyITypeLib"
+ +
[docs]PyIIDLike = Union[PyIID, str]
+ + +
[docs]def IsPyIID(value) -> TypeGuard[PyIID]: + return isinstance(value, IIDType)
+ + +
[docs]def IsPyITypeLib(value) -> TypeGuard[PyITypeLib]: + return type(value).__name__ == PyITypeLib
+ + +
[docs]def IsPyIIDLike(value) -> TypeGuard[PyIIDLike]: + return IsPyIID(value) or isinstance(value, str)
+ + +
[docs]def GetTypelibSpecs(iid: PyIIDLike) -> List[TypelibSpec]: + specs: List[TypelibSpec] = [] + + try: + key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "TypeLib") + key2 = win32api.RegOpenKey(key, str(iid)) + except win32api.error: + enum_keys = [] + else: + enum_keys = EnumKeys(key2) + + for version, tlbdesc in enum_keys: + major_minor = version.split(".", 1) + if len(major_minor) < 2: + major_minor.append("0") + major = major_minor[0] + minor = major_minor[1] + key3 = win32api.RegOpenKey(key2, str(version)) + try: + flags = int(win32api.RegQueryValue(key3, "FLAGS")) + except (win32api.error, ValueError): + flags = 0 + for lcid, _ in EnumKeys(key3): + try: + lcid = int(lcid) + except ValueError: + continue + try: + key4 = win32api.RegOpenKey(key3, "{}\\win32".format(lcid)) + except win32api.error: + try: + key4 = win32api.RegOpenKey(key3, "{}\\win64".format(lcid)) + except win32api.error: + continue + try: + dll, typ = win32api.RegQueryValueEx(key4, None) + if typ == win32con.REG_EXPAND_SZ: + dll = win32api.ExpandEnvironmentStrings(dll) + except win32api.error: + dll = None + spec = TypelibSpec(iid, lcid, major, minor, flags) + spec.dll = dll + spec.desc = tlbdesc + spec.ver_desc = tlbdesc + " (" + version + ")" + specs.append(spec) + + return specs
+ + +
[docs]def GetLatestTypelibSpec( + specs: Union[Sequence[TypelibSpec], PyIIDLike] +) -> Optional[TypelibSpec]: + spec: Optional[TypelibSpec] = None + + if IsPyIIDLike(specs): + specs = GetTypelibSpecs(specs) + + if len(specs) > 0: + specs = sorted(specs) + spec = specs[-1] + + return spec
+ + +
[docs]def LoadTypeLib(spec: Union[TypelibSpec, PyIIDLike]) -> Optional[PyITypeLib]: + tlb: Optional[PyITypeLib] = None + + if IsPyIIDLike(spec): + spec = GetLatestTypelibSpec(spec) + + if spec: + if spec.dll: + tlb = pythoncom.LoadTypeLib(spec.dll) + else: + tlb = pythoncom.LoadRegTypeLib( + spec.clsid, + spec.major, + spec.minor, + spec.lcid, + ) + + return tlb
+ + +
[docs]def BuildOleItems( + spec: Union[TypelibSpec, PyIIDLike], + tlb: Optional[PyITypeLib] = None, +) -> Tuple[ + Dict[PyIID, DispatchItem], + Dict[PyIID, EnumerationItem], + Dict[PyIID, RecordItem], + Dict[PyIID, VTableItem], +]: + oleItems: Dict[PyIID, DispatchItem] = {} + enumItems: Dict[PyIID, EnumerationItem] = {} + recordItems: Dict[PyIID, RecordItem] = {} + vtableItems: Dict[PyIID, VTableItem] = {} + + if IsPyIIDLike(spec): + spec = GetLatestTypelibSpec(spec) + + if spec: + if not tlb: + tlb = LoadTypeLib(spec) + progressInstance = None + gen = Generator(tlb, spec.dll, progressInstance, bBuildHidden=1) + oleItems, enumItems, recordItems, vtableItems = gen.BuildOleItemsFromType() + + return oleItems, enumItems, recordItems, vtableItems
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/rate_limiting/RateLimiter.html b/_modules/koapy/utils/rate_limiting/RateLimiter.html new file mode 100644 index 00000000..e9a1bd72 --- /dev/null +++ b/_modules/koapy/utils/rate_limiting/RateLimiter.html @@ -0,0 +1,235 @@ + + + + + + + + koapy.utils.rate_limiting.RateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.rate_limiting.RateLimiter

+import collections
+import threading
+import time
+
+from functools import wraps
+from typing import List
+
+from koapy.utils.logging.Logging import Logging
+
+
+
[docs]class RateLimiter: +
[docs] def check_sleep_seconds(self, *args, **kwargs): + return 0
+ +
[docs] def add_call_history(self, *args, **kwargs): + pass
+ +
[docs] def sleep_if_necessary(self, *args, **kwargs): + sleep_seconds = self.check_sleep_seconds(*args, **kwargs) + if sleep_seconds > 0: + time.sleep(sleep_seconds)
+ +
[docs] def wrap(self, func): + @wraps(func) + def wrapper(*args, **kwargs): + self.sleep_if_necessary(func, *args, **kwargs) + self.add_call_history(func, *args, **kwargs) + return func(*args, **kwargs) + + return wrapper
+ + def __call__(self, func): + return self.wrap(func)
+ + +
[docs]class TimeWindowRateLimiter(RateLimiter, Logging): + def __init__(self, period, calls): + super().__init__() + + self._period = period + self._calls = calls + + self._lock = threading.RLock() + self._clock = time.time + + if hasattr(time, "monotonic"): + self._clock = time.monotonic + + self._call_history = collections.deque(maxlen=self._calls) + +
[docs] def check_sleep_seconds(self, *args, **kwargs): + with self._lock: + if len(self._call_history) < self._calls: + return 0 + clock = self._clock() + remaining = self._call_history[0] + self._period - clock + return remaining
+ +
[docs] def add_call_history(self, *args, **kwargs): + with self._lock: + return self._call_history.append(self._clock())
+ +
[docs] def sleep_if_necessary(self, *args, **kwargs): + with self._lock: + sleep_seconds = self.check_sleep_seconds(*args, **kwargs) + if sleep_seconds > 0: + time.sleep(sleep_seconds)
+ + +
[docs]class CompositeTimeWindowRateLimiter(RateLimiter): + def __init__(self, limiters: List[RateLimiter]): + super().__init__() + + self._lock = threading.RLock() + self._limiters = limiters + +
[docs] def check_sleep_seconds(self, *args, **kwargs): + with self._lock: + return max( + limiter.check_sleep_seconds(*args, **kwargs) + for limiter in self._limiters + )
+ +
[docs] def add_call_history(self, *args, **kwargs): + with self._lock: + for limiter in self._limiters: + limiter.add_call_history(*args, **kwargs)
+ +
[docs] def sleep_if_necessary(self, *args, **kwargs): + with self._lock: + sleep_seconds = self.check_sleep_seconds(*args, **kwargs) + if sleep_seconds > 0: + time.sleep(sleep_seconds)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor.html b/_modules/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor.html new file mode 100644 index 00000000..84deab4b --- /dev/null +++ b/_modules/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor.html @@ -0,0 +1,296 @@ + + + + + + + + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor

+import atexit
+import functools
+import queue
+
+from concurrent.futures import Executor, Future
+from queue import Queue
+from threading import RLock
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+from koapy.compat.pyside2.QtCore import QObject, Qt, Signal
+from koapy.utils.logging.pyside2.QThreadLogging import QThreadLogging
+from koapy.utils.rate_limiting.RateLimiter import RateLimiter
+
+
+
[docs]class QRateLimitedExecutorRunnable: + def __init__( + self, + limiter: RateLimiter, + future: Future, + fn: Callable[..., Any], + args: Union[Tuple[Any], List[Any]], + kwargs: Dict[str, Any], + ): + self._limiter = limiter + self._future = future + self._fn = fn + self._args = args + self._kwargs = kwargs + +
[docs] def check_sleep_seconds(self): + return self._limiter.check_sleep_seconds(self._fn, *self._args, **self._kwargs)
+ +
[docs] def add_call_history(self): + return self._limiter.add_call_history(self._fn, *self._args, **self._kwargs)
+ +
[docs] def sleep_if_necessary(self): + return self._limiter.sleep_if_necessary(self._fn, *self._args, **self._kwargs)
+ +
[docs] def run(self): + if not self._future.set_running_or_notify_cancel(): + return + try: + self.add_call_history() + result = self._fn(*self._args, **self._kwargs) + except BaseException as exc: # pylint: disable=broad-except + self._future.set_exception(exc) + # break a reference cycle with the exception 'exc' + self = None # pylint: disable=self-cls-assignment + else: + self._future.set_result(result)
+ +
[docs] def cancel(self): + return self._future.cancel()
+ +
[docs] def result(self): + return self._future.result()
+ + +
[docs]class QRateLimitedExecutorDecoratedFunction: + def __init__(self, func, limiter: RateLimiter, executor: Executor): + self._func = func + self._limiter = limiter + self._executor = executor + + functools.update_wrapper(self, func) + self._func_limited = self._limiter.wrap(self._func) + +
[docs] def call(self, *args, **kwargs): + return self._func_limited(*args, **kwargs)
+ +
[docs] def async_call(self, *args, **kwargs): + return self._executor.submit(self._func, *args, **kwargs)
+ + def __call__(self, *args, **kwargs): + return self.call(*args, **kwargs)
+ + +
[docs]class QRateLimitedExecutor(QThreadLogging, Executor): + +
[docs] readyRunnable = Signal(QRateLimitedExecutorRunnable)
+ + def __init__(self, limiter: RateLimiter, parent: Optional[QObject] = None): + QThreadLogging.__init__(self, parent) + Executor.__init__(self) + + self._limiter = limiter + self._parent = parent + + self._runnable_queue: Queue = Queue() + self._sentinel = object() + + self._shutdown = False + self._shutdown_lock = RLock() + + self.readyRunnable.connect(self.onReadyRunnable, Qt.QueuedConnection) + + atexit.register(self.shutdown) + + def __del__(self): + atexit.unregister(self.shutdown) + +
[docs] def run(self): + while True: + runnable = self._runnable_queue.get() + if runnable is not self._sentinel: + runnable.sleep_if_necessary() + self.readyRunnable.emit(runnable) + try: + runnable.result() # wait until the emitted runnable finishes + except: # pylint: disable=bare-except + pass + del runnable + continue + if self._shutdown: + return
+ +
[docs] def onReadyRunnable(self, runnable: QRateLimitedExecutorRunnable): + runnable.run()
+ +
[docs] def submit( + self, fn: Callable[..., Any], *args, **kwargs + ): # pylint: disable=arguments-differ + with self._shutdown_lock: + if self._shutdown: + raise RuntimeError("Cannot schedule new futures after shutdown") + future = Future() + runnable = QRateLimitedExecutorRunnable( + self._limiter, future, fn, args, kwargs + ) + self._runnable_queue.put(runnable) + return future
+ +
[docs] def shutdown( + self, wait: bool = True, cancel_futures: bool = False + ): # pylint: disable=arguments-differ + with self._shutdown_lock: + self._shutdown = True + if cancel_futures: + while True: + try: + runnable = self._runnable_queue.get_nowait() + except queue.Empty: + break + if runnable is not self._sentinel: + runnable.cancel() + self._runnable_queue.put(self._sentinel) + if wait: + self.wait()
+ +
[docs] def wrap(self, func: Callable[..., Any]): + return QRateLimitedExecutorDecoratedFunction(func, self._limiter, self)
+ + def __call__(self, func: Callable[..., Any]): + return self.wrap(func)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/recursion.html b/_modules/koapy/utils/recursion.html new file mode 100644 index 00000000..e9d45db8 --- /dev/null +++ b/_modules/koapy/utils/recursion.html @@ -0,0 +1,190 @@ + + + + + + + + koapy.utils.recursion — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.recursion

+"""
+"""
+
+"""
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+"""
+
+# https://github.com/andrewp-as-is/recursion-detect.py
+
+import inspect
+
+
+
[docs]def depth(): + """return recursion depth. 0 if no recursion""" + counter = 0 + frames = inspect.getouterframes(inspect.currentframe())[1:] + top_frame = inspect.getframeinfo(frames[0][0]) + for frame, _, _, _, _, _ in frames[1:]: + (path, line_number, func_name, lines, index) = inspect.getframeinfo(frame) + if path == top_frame[0] and func_name == top_frame[2]: + counter += 1 + return counter
+ + +__all__ = ["depth"] +
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/serialization.html b/_modules/koapy/utils/serialization.html new file mode 100644 index 00000000..023a6582 --- /dev/null +++ b/_modules/koapy/utils/serialization.html @@ -0,0 +1,184 @@ + + + + + + + + koapy.utils.serialization — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.serialization

+import io
+import json
+import os
+
+
+
[docs]class JsonSerializable: +
[docs] def to_dict(self): + return dict(self.__dict__)
+ + @classmethod +
[docs] def from_dict(cls, dic): + output = cls() + for name in output.__dict__: + setattr(output, name, dic.get(name)) + return output
+ +
[docs] def to_json(self, f=None, encoding=None): + if f is None: + return json.dumps(self.to_dict()) + elif isinstance(f, str): + with open(f, "w", encoding=encoding) as f: + return json.dump(self.to_dict(), f) + elif isinstance(f, io.TextIOBase): + return json.dump(self.to_dict(), f) + else: + raise ValueError("Unsupported argument type: %s" % type(f))
+ + @classmethod +
[docs] def from_json(cls, jsn, encoding=None): + if isinstance(jsn, str): + if jsn.startswith("{") and jsn.endswith("}"): + dic = json.loads(jsn) + elif os.path.exists(jsn): + with open(jsn, "r", encoding=encoding) as f: + dic = json.load(f) + else: + dic = json.loads(jsn) + elif isinstance(jsn, io.TextIOBase): + dic = json.load(jsn) + else: + raise ValueError("Unsupported argument type: %s" % type(jsn)) + return cls.from_dict(dic)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/SQLiteFileLibrary.html b/_modules/koapy/utils/store/SQLiteFileLibrary.html new file mode 100644 index 00000000..05ad44ca --- /dev/null +++ b/_modules/koapy/utils/store/SQLiteFileLibrary.html @@ -0,0 +1,283 @@ + + + + + + + + koapy.utils.store.SQLiteFileLibrary — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.SQLiteFileLibrary

+import pandas as pd
+import pytz
+
+from sqlalchemy import create_engine, inspect, select
+from sqlalchemy.schema import DropTable, MetaData, Table
+
+from .sqlalchemy.Timestamp import Timestamp
+
+
+
[docs]class SQLiteFileLibrary: + def __init__(self, filename): + self._engine = create_engine("sqlite:///" + filename) + self._inspector = inspect(self._engine) + +
[docs] def list_symbols(self): + return self._inspector.get_table_names()
+ +
[docs] def has_symbol(self, symbol): + return self._inspector.has_table(symbol)
+ +
[docs] def write(self, symbol, data): + index_original_names = [name for name in data.index.names] + index_table_names = [ + name if name is not None else "index_%d" % i + for i, name in enumerate(data.index.names) + ] + + datetime_columns = [ + (name, dtype) + for name, dtype in data.dtypes.items() + if pd.api.types.is_datetime64_any_dtype(dtype) + ] + column_timezones = { + name: str(dtype.tz) + for name, dtype in datetime_columns + if hasattr(dtype, "tz") + } + + index_label = index_table_names + dtype = { + name: Timestamp(getattr(dtype, "tz", False)) + for name, dtype in datetime_columns + } + + index_col = index_table_names + parse_dates = [name for name, dtype in datetime_columns] + + pandas_metadata = { + "read_sql_table": { + "index_col": index_col, + "parse_dates": parse_dates, + "index_names": index_original_names, + "column_timezones": column_timezones, + }, + } + + to_sql_kwargs = { + "index_label": index_label, + "dtype": dtype, + "if_exists": "replace", + } + data.to_sql(symbol, self._engine, **to_sql_kwargs) + + return data
+ +
[docs] def read_as_dataframe( + self, symbol, time_column=None, start_time=None, end_time=None + ): + index_col = ["Date"] + parse_dates = ["Date"] + read_sql_table_kwargs = { + "index_col": index_col, + "parse_dates": parse_dates, + } + data = pd.read_sql_table(symbol, self._engine, **read_sql_table_kwargs) + index_names = index_col + index_names = tuple(index_names) + if len(data.index.names) == 1: + index_names = index_names[0] + data.index.rename(index_names, inplace=True) + column_timezones = {} + for column_name in parse_dates: + timezone = column_timezones.get(column_name, Timestamp.local_timezone) + if isinstance(timezone, str): + timezone = pytz.timezone(timezone) + data[column_name] = ( + data[column_name].dt.tz_localize(Timestamp.utc).dt.tz_convert(timezone) + ) + if column_name not in column_timezones: + data[column_name] = data[column_name].dt.tz_localize(None) + return data
+ +
[docs] def read_as_cursor(self, symbol, time_column=None, start_time=None, end_time=None): + records = Table(symbol, MetaData(), autoload_with=self._engine) + statement = select(records) + + if time_column is not None: + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + + if start_time is not None: + start_time = pd.Timestamp(start_time) + if time_column is None: + time_column = 0 + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + if Timestamp.is_naive(start_time): + start_time = start_time.tz_localize(Timestamp.local_timezone) + start_time = start_time.astimezone(Timestamp.utc) + statement = statement.where( + time_column >= start_time + ) # pylint: disable=unsubscriptable-object + + if end_time is not None: + end_time = pd.Timestamp(end_time) + if time_column is None: + time_column = 0 + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + if Timestamp.is_naive(end_time): + end_time = end_time.tz_localize(Timestamp.local_timezone) + end_time = end_time.astimezone(Timestamp.utc) + statement = statement.where( + time_column <= end_time + ) # pylint: disable=unsubscriptable-object + + data = self._engine.execute(statement) + return data
+ +
[docs] def read(self, *args, **kwargs): + return self.read_as_dataframe(*args, **kwargs)
+ +
[docs] def delete(self, symbol): + table = Table(symbol, MetaData(), autoload_with=self._engine) + self._engine.execute(DropTable(table), if_exists=True)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/SQLiteStore.html b/_modules/koapy/utils/store/SQLiteStore.html new file mode 100644 index 00000000..88d8f4e9 --- /dev/null +++ b/_modules/koapy/utils/store/SQLiteStore.html @@ -0,0 +1,224 @@ + + + + + + + + koapy.utils.store.SQLiteStore — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.SQLiteStore

+from sqlalchemy import create_engine, inspect
+
+from .sqlalchemy.Base import Base
+from .sqlalchemy.Library import Library
+from .sqlalchemy.Session import Session
+from .SQLiteStoreLibrary import SQLiteStoreLibrary
+
+
+
[docs]class SQLiteStore: + def __init__(self, filename): + self._filename = filename + self._engine = create_engine("sqlite:///" + self._filename) + + Session.configure(bind=self._engine) + + inspector = inspect(self._engine) + table_names = inspector.get_table_names() + + if len(table_names) == 0: + Base.metadata.create_all(self._engine) + inspector = inspect(self._engine) + table_names = inspector.get_table_names() + + assert all(table_name in table_names for table_name in Base.metadata.tables) + + self._session = Session() + self._library_cache = {} + +
[docs] def list_libraries(self): + libraries = self._session.query(Library).all() + libraries = [library.name for library in libraries] + return libraries
+ + def _get_library(self, library): + library = self._session.query(Library).filter(Library.name == library).one() + return library + +
[docs] def library_exists(self, library): + try: + _library = self._get_library(library) + return True + except: + return False
+ +
[docs] def initialize_library(self, library): + library_name = library + if not self.library_exists(library_name): + library = Library(name=library_name) + try: + self._session.add(library) + self._session.commit() + except: + self._session.rollback() + raise
+ +
[docs] def get_library(self, library): + library_name = library + if library_name in self._library_cache: + return self._library_cache[library_name] + library = self._get_library(library) + library = SQLiteStoreLibrary(self, library) + self._library_cache[library_name] = library + return library
+ +
[docs] def get_or_create_library(self, library): + if not self.library_exists(library): + self.initialize_library(library) + library = self.get_library(library) + return library
+ +
[docs] def delete_library(self, library): + library_name = library + library = self._get_library(library_name) + try: + library.delete() + self._session.commit() + except: + self._session.rollback() + raise
+ + def __getitem__(self, library): + return self.get_library(library)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/SQLiteStoreLibrary.html b/_modules/koapy/utils/store/SQLiteStoreLibrary.html new file mode 100644 index 00000000..38c77e08 --- /dev/null +++ b/_modules/koapy/utils/store/SQLiteStoreLibrary.html @@ -0,0 +1,454 @@ + + + + + + + + koapy.utils.store.SQLiteStoreLibrary — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.SQLiteStoreLibrary

+import hashlib
+
+import pandas as pd
+import pytz
+
+from sqlalchemy import select
+from sqlalchemy.orm.exc import NoResultFound
+from sqlalchemy.schema import MetaData, Table
+
+from .misc.VersionedItem import VersionedItem
+from .sqlalchemy.Timestamp import Timestamp
+
+
+
[docs]class SQLiteStoreLibrary: + def __init__(self, store, library): + self._store = store + self._library = library + + self._engine = self._store._engine + self._session = self._store._session + +
[docs] def list_symbols(self, all_symbols=False, snapshot=None): + if snapshot is not None: + snapshot = self._library.get_snapshot(snapshot) + symbols = snapshot.get_symbols() + else: + symbols = self._library.get_symbols(deleted=all_symbols) + symbols = [symbol.name for symbol in symbols] + return symbols
+ +
[docs] def has_symbol(self, symbol): + try: + _symbol = self._library.get_symbol(symbol) + return True + except NoResultFound: + return False
+ +
[docs] def list_versions(self, symbol=None, snapshot=None, latest_only=False): + if symbol is not None: + symbol = self._library.get_symbol(symbol) + versions = symbol.get_versions() + elif snapshot is not None: + snapshot = self._library.get_snapshot(snapshot) + versions = snapshot.get_versions() + elif latest_only: + versions = self._library.get_latest_versions() + else: + versions = self._library.get_versions() + versions = [ + { + "symbol": version.symbol.name, + "version": version.version, + "deleted": version.deleted, + "timestamp": version.timestamp, + "snapshots": [snapshot.name for snapshot in version.get_snapshots()], + } + for version in versions + ] + return versions
+ + def _hash_data(self, data): + return hashlib.sha256( + pd.util.hash_pandas_object(data).values.tobytes() + ).hexdigest() + +
[docs] def write(self, symbol, data, metadata=None, prune_previous_version=True, **kwargs): + symbol_name = symbol + try: + symbol = self._library.get_or_create_symbol(symbol_name) + + if data is None: + _version = symbol.create_new_version( + user_metadata=metadata, deleted=metadata and metadata.get("deleted") + ) + self._session.commit() + else: + index_original_names = [name for name in data.index.names] + index_table_names = [ + name if name is not None else "index_%d" % i + for i, name in enumerate(data.index.names) + ] + + datetime_columns = [ + (name, dtype) + for name, dtype in data.dtypes.items() + if pd.api.types.is_datetime64_any_dtype(dtype) + ] + column_timezones = { + name: str(dtype.tz) + for name, dtype in datetime_columns + if hasattr(dtype, "tz") + } + + index_label = index_table_names + dtype = { + name: Timestamp(getattr(dtype, "tz", False)) + for name, dtype in datetime_columns + } + + index_col = index_table_names + parse_dates = [name for name, dtype in datetime_columns] + + pandas_metadata = { + "read_sql_table": { + "index_col": index_col, + "parse_dates": parse_dates, + "index_names": index_original_names, + "column_timezones": column_timezones, + }, + } + + table_name = self._hash_data(data) + _version = symbol.create_new_version( + table_name=table_name, + user_metadata=metadata, + pandas_metadata=pandas_metadata, + deleted=metadata and metadata.get("deleted"), + ) + self._session.commit() + + to_sql_kwargs = { + "index_label": index_label, + "dtype": dtype, + "if_exists": "replace", + } + data.to_sql(table_name, self._engine, **to_sql_kwargs) + except: + self._session.rollback() + raise + + if prune_previous_version: + self._prune_previous_versions(symbol_name, **kwargs) + + return self.read(symbol_name)
+ + def _get_version(self, symbol, as_of=None): + symbol_name = symbol + symbol = self._library.get_symbol(symbol_name) + + if as_of is None: + version = symbol.get_latest_version() + elif isinstance(as_of, int): + version = symbol.get_version_by_number(as_of) + elif isinstance(as_of, str): + snapshot = self._library.get_snapshot(as_of) + version = snapshot.get_version_of_symbol(symbol) + else: + raise ValueError("Invalid as_of argument") + + return version + +
[docs] def read_as_dataframe( + self, symbol, as_of=None, time_column=None, start_time=None, end_time=None + ): + symbol_name = symbol + version = self._get_version(symbol_name, as_of) + + data = None + + if version.table_name is not None: + read_sql_table_kwargs = { + "index_col": version.pandas_metadata["read_sql_table"]["index_col"], + "parse_dates": version.pandas_metadata["read_sql_table"]["parse_dates"], + } + data = pd.read_sql_table( + version.table_name, self._engine, **read_sql_table_kwargs + ) + index_names = version.pandas_metadata["read_sql_table"]["index_names"] + index_names = tuple(index_names) + if len(data.index.names) == 1: + index_names = index_names[0] + data.index.rename(index_names, inplace=True) # pylint: disable=no-member + column_timezones = version.pandas_metadata["read_sql_table"][ + "column_timezones" + ] + for column_name in version.pandas_metadata["read_sql_table"]["parse_dates"]: + timezone = column_timezones.get(column_name, Timestamp.local_timezone) + if isinstance(timezone, str): + timezone = pytz.timezone(timezone) + data[column_name] = ( + data[column_name] + .dt.tz_localize(Timestamp.utc) + .dt.tz_convert(timezone) + ) + if column_name not in column_timezones: + data[column_name] = data[column_name].dt.tz_localize(None) + + return VersionedItem( + self._library.name, + symbol_name, + version.version, + version.timestamp, + data, + version.user_metadata, + )
+ +
[docs] def read_as_cursor( + self, symbol, as_of=None, time_column=None, start_time=None, end_time=None + ): + symbol_name = symbol + version = self._get_version(symbol_name, as_of) + + cursor = None + + if version.table_name is not None: + records = Table(version.table_name, MetaData(), autoload_with=self._engine) + statement = select(records) + + if time_column is not None: + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + + if start_time is not None: + start_time = pd.Timestamp(start_time) + if time_column is None: + time_column = 0 + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + if Timestamp.is_naive(start_time): + start_time = start_time.tz_localize(Timestamp.local_timezone) + start_time = start_time.astimezone(Timestamp.utc) + statement = statement.where( + time_column >= start_time + ) # pylint: disable=unsubscriptable-object + + if end_time is not None: + end_time = pd.Timestamp(end_time) + if time_column is None: + time_column = 0 + time_column = records.columns[ + time_column + ] # pylint: disable=unsubscriptable-object + statement = statement.order_by(time_column) + if Timestamp.is_naive(end_time): + end_time = end_time.tz_localize(Timestamp.local_timezone) + end_time = end_time.astimezone(Timestamp.utc) + statement = statement.where( + time_column <= end_time + ) # pylint: disable=unsubscriptable-object + + statement = statement.execution_options(stream_results=True) + + cursor = self._session.execute(statement) + + return VersionedItem( + self._library.name, + symbol_name, + version.version, + version.timestamp, + cursor, + version.user_metadata, + )
+ +
[docs] def read(self, *args, **kwargs): + return self.read_as_dataframe(*args, **kwargs)
+ + def _prune_previous_versions(self, symbol, keep_mins=120): + symbol_name = symbol + symbol = self._library.get_symbol(symbol_name) + prunable_verions = symbol.get_prunable_versions(keep_mins) + try: + for version in prunable_verions: + version.delete() + self._session.commit() + except: + self._session.rollback() + raise + + def _delete_version(self, symbol, version): + symbol = self._library.get_symbol(symbol) + version = symbol.get_version_by_number(version, deleted=True) + try: + version.delete() + self._session.commit() + except: + self._session.rollback() + raise + +
[docs] def delete(self, symbol): + symbol_name = symbol + symbol = self._library.get_symbol(symbol_name) + _sentinel = self.write( + symbol_name, None, prune_previous_version=False, metadata={"deleted": True} + ) + self._prune_previous_versions(symbol_name, 0) + assert not self.has_symbol(symbol_name)
+ +
[docs] def list_snapshots(self): + snapshots = self._library.snapshots + snapshots = [snapshot.name for snapshot in snapshots] + return snapshots
+ +
[docs] def snapshot(self, snapshot): + try: + self._library.create_snapshot(snapshot) + self._session.commit() + except: + self._session.rollback() + raise
+ +
[docs] def delete_snapshot(self, snapshot): + snapshot = self._library.get_snapshot(snapshot) + try: + snapshot.delete() + self._session.commit() + except: + self._session.rollback() + raise
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/misc/VersionedItem.html b/_modules/koapy/utils/store/misc/VersionedItem.html new file mode 100644 index 00000000..58af9d29 --- /dev/null +++ b/_modules/koapy/utils/store/misc/VersionedItem.html @@ -0,0 +1,162 @@ + + + + + + + + koapy.utils.store.misc.VersionedItem — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.misc.VersionedItem

+
[docs]class VersionedItem: + def __init__(self, library, symbol, version, timestamp, data, metadata): + self.library = library + self.symbol = symbol + self.version = version + self.timestamp = timestamp + self.data = data + self.metadata = metadata + + def __repr__(self): + return "<VersionedItem(library={!r}, symbol={!r}, version={!r}, timestamp='{}', data=<{}.{} at {}>, metadata={!r})>".format( + self.library, + self.symbol, + self.version, + self.timestamp, + type(self.data).__module__, + type(self.data).__name__, + hex(id(self.data)), + self.metadata, + )
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Base.html b/_modules/koapy/utils/store/sqlalchemy/Base.html new file mode 100644 index 00000000..cc55c189 --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Base.html @@ -0,0 +1,145 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Base — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Base

+from sqlalchemy.orm import declarative_base
+
+
[docs]Base = declarative_base()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Library.html b/_modules/koapy/utils/store/sqlalchemy/Library.html new file mode 100644 index 00000000..76b55cbc --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Library.html @@ -0,0 +1,271 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Library — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Library

+from sqlalchemy import Column, Integer, String, func
+from sqlalchemy.orm import aliased, object_session, relationship
+from sqlalchemy.orm.exc import NoResultFound
+
+from .Base import Base
+from .Snapshot import Snapshot
+from .SnapshotAssociation import SnapshotAssociation
+from .Symbol import Symbol
+from .Version import Version
+
+
+
[docs]class Library(Base): + __tablename__ = "libraries" + +
[docs] id = Column(Integer, primary_key=True)
+
[docs] name = Column(String, unique=True, index=True, nullable=False)
+ +
[docs] symbols = relationship("Symbol", back_populates="library")
+
[docs] snapshots = relationship("Snapshot", back_populates="library")
+ +
[docs] def get_symbol(self, symbol, deleted=False): + symbol_name = symbol + session = object_session(self) + symbol = ( + session.query(Symbol).with_parent(self).filter(Symbol.name == symbol_name) + ) + symbol = symbol.one() + if not deleted: + _version = symbol.get_latest_version() + return symbol
+ +
[docs] def get_or_create_symbol(self, symbol): + symbol_name = symbol + try: + symbol = self.get_symbol(symbol_name, deleted=True) + except NoResultFound: + symbol = Symbol(name=symbol_name) + self.symbols.append(symbol) + return symbol
+ +
[docs] def get_symbols(self, deleted=False): + if deleted: + return self.symbols + + session = object_session(self) + + symbols = session.query(Symbol).with_parent(self) + + versions = session.query(Version, func.max(Version.version)).group_by( + Version.symbol_id + ) + version = aliased(Version, alias=versions.subquery()) + versions = session.query(version) + + if not deleted: + versions = versions.filter(version.deleted != True) + + symbols = symbols.join(versions.subquery()) + symbols = symbols.all() + return symbols
+ +
[docs] def get_versions(self, deleted=False): + session = object_session(self) + + symbols = session.query(Symbol).with_parent(self) + versions = session.query(Version).join(symbols.subquery()) + + if not deleted: + versions = versions.filter(Version.deleted != True) + + versions = versions.all() + return versions
+ +
[docs] def get_latest_versions(self, deleted=False): + session = object_session(self) + + symbols = session.query(Symbol).with_parent(self) + + versions = session.query(Version, func.max(Version.version)).group_by( + Version.symbol_id + ) + version = aliased(Version, alias=versions.subquery()) + versions = session.query(version) + + if not deleted: + versions = versions.filter(version.deleted != True) + + versions = versions.join(symbols.subquery()) + versions = versions.all() + return versions
+ +
[docs] def get_snapshot(self, snapshot): + snapshot_name = snapshot + session = object_session(self) + snapshot = ( + session.query(Snapshot) + .with_parent(self) + .filter(Snapshot.name == snapshot_name) + .one() + ) + return snapshot
+ +
[docs] def create_snapshot(self, snapshot): + snapshot_name = snapshot + snapshot = Snapshot(name=snapshot_name) + + versions = self.get_latest_versions() + associations = [SnapshotAssociation(version=version) for version in versions] + snapshot.versions.extend(associations) + + self.snapshots.append(snapshot) + return snapshot
+ +
[docs] def delete(self): + session = object_session(self) + + symbols = session.query(Symbol).with_parent(self) + versions = session.query(Version).join(symbols) + + snapshots = session.query(Snapshot).with_parent(self) + associations = session.query(SnapshotAssociation).join(snapshots) + + associations.delete() + snapshots.delete() + + versions.delete() + symbols.delete() + + session.delete(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Session.html b/_modules/koapy/utils/store/sqlalchemy/Session.html new file mode 100644 index 00000000..78e4aaeb --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Session.html @@ -0,0 +1,145 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Session — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Session

+from sqlalchemy.orm import sessionmaker
+
+
[docs]Session = sessionmaker()
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Snapshot.html b/_modules/koapy/utils/store/sqlalchemy/Snapshot.html new file mode 100644 index 00000000..6e1b3589 --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Snapshot.html @@ -0,0 +1,205 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Snapshot — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Snapshot

+from sqlalchemy import Column, ForeignKey, Integer, String, UniqueConstraint
+from sqlalchemy.orm import object_session, relationship
+from sqlalchemy.sql.functions import current_timestamp
+
+from .Base import Base
+from .SnapshotAssociation import SnapshotAssociation
+from .Symbol import Symbol
+from .Timestamp import Timestamp
+from .Version import Version
+
+
+
[docs]class Snapshot(Base): + __tablename__ = "snapshots" + +
[docs] id = Column(Integer, primary_key=True)
+
[docs] name = Column(String, index=True, nullable=False)
+ +
[docs] timestamp = Column(Timestamp(timezone=True), server_default=current_timestamp())
+ +
[docs] library_id = Column(Integer, ForeignKey("libraries.id"), nullable=False)
+
[docs] library = relationship("Library", back_populates="snapshots")
+ +
[docs] versions = relationship("SnapshotAssociation", back_populates="snapshot")
+ + __table_args__ = (UniqueConstraint("library_id", "name"),) + +
[docs] def get_symbols(self): + session = object_session(self) + associations = session.query(SnapshotAssociation).with_parent(self) + versions = session.query(Version).join(associations.subquery()) + symbols = session.query(Symbol).join(versions.subquery()) + symbols = symbols.all() + return symbols
+ +
[docs] def get_versions(self): + session = object_session(self) + associations = session.query(SnapshotAssociation).with_parent(self) + versions = session.query(Version).join(associations.subquery()) + versions = versions.all() + return versions
+ +
[docs] def get_version_of_symbol(self, symbol): + session = object_session(self) + if isinstance(symbol, str): + symbol = ( + session.query(Symbol) + .filter(Symbol.library_id == self.library_id and Symbol.name == symbol) + .one() + ) + associations = session.query(SnapshotAssociation).with_parent(self) + version = ( + session.query(Version) + .with_parent(symbol) + .join(associations.subquery()) + .one() + ) + return version
+ +
[docs] def delete(self): + session = object_session(self) + associations = session.query(SnapshotAssociation).with_parent(self) + associations.delete() + session.delete(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/SnapshotAssociation.html b/_modules/koapy/utils/store/sqlalchemy/SnapshotAssociation.html new file mode 100644 index 00000000..e3982a9f --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/SnapshotAssociation.html @@ -0,0 +1,156 @@ + + + + + + + + koapy.utils.store.sqlalchemy.SnapshotAssociation — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.SnapshotAssociation

+from sqlalchemy import Column, ForeignKey, Integer
+from sqlalchemy.orm import relationship
+
+from .Base import Base
+
+
+
[docs]class SnapshotAssociation(Base): + __tablename__ = "snapshot_associations" + +
[docs] snapshot_id = Column(Integer, ForeignKey("snapshots.id"), primary_key=True)
+
[docs] version_id = Column(Integer, ForeignKey("versions.id"), primary_key=True)
+ +
[docs] snapshot = relationship("Snapshot", back_populates="versions")
+
[docs] version = relationship("Version", back_populates="snapshots")
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Symbol.html b/_modules/koapy/utils/store/sqlalchemy/Symbol.html new file mode 100644 index 00000000..2dae836e --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Symbol.html @@ -0,0 +1,249 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Symbol — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Symbol

+import pandas as pd
+
+from sqlalchemy import Column, ForeignKey, Integer, String, UniqueConstraint, func
+from sqlalchemy.orm import aliased, object_session, relationship
+from sqlalchemy.orm.exc import NoResultFound
+
+from .Base import Base
+from .SnapshotAssociation import SnapshotAssociation
+from .Version import Version
+
+
+
[docs]class Symbol(Base): + __tablename__ = "symbols" + +
[docs] id = Column(Integer, primary_key=True)
+
[docs] name = Column(String, index=True, nullable=False)
+ +
[docs] library_id = Column(Integer, ForeignKey("libraries.id"), nullable=False)
+
[docs] library = relationship("Library", back_populates="symbols")
+ +
[docs] versions = relationship( + "Version", back_populates="symbol", order_by="Version.version" + )
+ + __table_args__ = (UniqueConstraint("library_id", "name"),) + +
[docs] def get_versions(self, deleted=False): + """ + versions = self.versions + if not deleted: + versions = [version for version in versions if not version.deleted] + """ + session = object_session(self) + versions = session.query(Version).with_parent(self) + version = aliased(Version, alias=versions.subquery()) + versions = session.query(version) + if not deleted: + versions = versions.filter(version.deleted != True) + versions = versions.order_by(version.version) + versions = versions.all() + return versions
+ +
[docs] def get_latest_version(self, deleted=False): + """ + versions = self.versions + if len(versions) == 0: + raise NoResultFound + latest_version = self.versions[-1] + if not deleted and latest_version.deleted: + raise NoResultFound + """ + session = object_session(self) + latest_version = session.query(Version, func.max(Version.version)).with_parent( + self + ) + version = aliased(Version, alias=latest_version.subquery()) + latest_version = session.query(version) + if not deleted: + latest_version = latest_version.filter(version.deleted != True) + latest_version = latest_version.one() + return latest_version
+ +
[docs] def create_new_version( + self, table_name=None, user_metadata=None, pandas_metadata=None, deleted=None + ): + try: + latest_version = self.get_latest_version() + except NoResultFound: + next_version = 0 + else: + next_version = latest_version.version + 1 + new_version = Version( + version=next_version, + table_name=table_name, + user_metadata=user_metadata, + pandas_metadata=pandas_metadata, + deleted=deleted, + ) + self.versions.append(new_version) + return new_version
+ +
[docs] def get_version_by_number(self, version_number, deleted=False): + session = object_session(self) + version = ( + session.query(Version) + .with_parent(self) + .filter(Version.version == version_number) + ) + if not deleted: + version = version.filter(Version.deleted != True) + version = version.one() + return version
+ +
[docs] def get_prunable_versions(self, keep_mins=120): + session = object_session(self) + versions = session.query(Version).with_parent(self) + latest_version = self.get_latest_version(deleted=True) + keep_mins_seconds = keep_mins * 60 + latest_timestamp = latest_version.timestamp + oldest_timestamp = latest_timestamp - pd.Timedelta(keep_mins_seconds, unit="s") + prunable_verions = ( + versions.outerjoin(SnapshotAssociation) + .filter(SnapshotAssociation.version_id == None) + .filter(Version.timestamp < oldest_timestamp) + ) + prunable_verions = prunable_verions.all() + return prunable_verions
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Timestamp.html b/_modules/koapy/utils/store/sqlalchemy/Timestamp.html new file mode 100644 index 00000000..2d4345ac --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Timestamp.html @@ -0,0 +1,189 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Timestamp — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Timestamp

+import datetime
+import inspect
+
+import pytz
+
+from sqlalchemy import DateTime
+from sqlalchemy.types import TypeDecorator
+
+
+
[docs]class Timestamp(TypeDecorator): # pylint: disable=abstract-method + +
[docs] impl = DateTime
+
[docs] cache_ok = True
+ +
[docs] signature = inspect.signature(impl)
+ +
[docs] utc = datetime.timezone.utc
+
[docs] local_timezone = datetime.datetime.now().astimezone().tzinfo
+ + def __init__(self, *args, **kwargs): + self._timezone = self.local_timezone + bound = self.signature.bind(*args, **kwargs) + bound.apply_defaults() + if bound.arguments["timezone"]: + if not isinstance(bound.arguments["timezone"], bool): + self._timezone = bound.arguments["timezone"] + bound.arguments["timezone"] = True + if isinstance(self._timezone, str): + self._timezone = pytz.timezone(self._timezone) + super().__init__(*bound.args, **bound.kwargs) + + @classmethod +
[docs] def is_naive(cls, value): + return value.tzinfo is None or value.tzinfo.utcoffset(value) is None
+ +
[docs] def process_bind_param(self, value, dialect): + if self.is_naive(value): + value = value.replace(tzinfo=self.local_timezone) + return value.astimezone(self.utc)
+ +
[docs] def process_result_value(self, value, dialect): + if self.is_naive(value): + value = value.replace(tzinfo=self.utc) + value = value.astimezone(self._timezone) + if not self.timezone: + value = value.replace(tzinfo=None) + return value
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/store/sqlalchemy/Version.html b/_modules/koapy/utils/store/sqlalchemy/Version.html new file mode 100644 index 00000000..bdae35ce --- /dev/null +++ b/_modules/koapy/utils/store/sqlalchemy/Version.html @@ -0,0 +1,204 @@ + + + + + + + + koapy.utils.store.sqlalchemy.Version — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.store.sqlalchemy.Version

+from sqlalchemy import (
+    Boolean,
+    Column,
+    ForeignKey,
+    Integer,
+    PickleType,
+    String,
+    UniqueConstraint,
+)
+from sqlalchemy.orm import object_session, relationship
+from sqlalchemy.schema import DropTable, MetaData, Table
+from sqlalchemy.sql.functions import current_timestamp
+
+from .Base import Base
+from .Timestamp import Timestamp
+
+
+
[docs]class Version(Base): + __tablename__ = "versions" + +
[docs] id = Column(Integer, primary_key=True)
+
[docs] version = Column(Integer, nullable=False)
+ +
[docs] table_name = Column(String)
+
[docs] user_metadata = Column(PickleType)
+
[docs] pandas_metadata = Column(PickleType)
+ +
[docs] deleted = Column(Boolean, default=False)
+ +
[docs] timestamp = Column(Timestamp(timezone=True), server_default=current_timestamp())
+ +
[docs] symbol_id = Column(Integer, ForeignKey("symbols.id"))
+
[docs] symbol = relationship("Symbol", back_populates="versions")
+ +
[docs] snapshots = relationship("SnapshotAssociation", back_populates="version")
+ + __table_args__ = (UniqueConstraint("symbol_id", "version"),) + +
[docs] def get_snapshots(self): + # quick fix fir circular dependency + from .Snapshot import Snapshot + from .SnapshotAssociation import SnapshotAssociation + + session = object_session(self) + snapshots = session.query(SnapshotAssociation).with_parent(self) + snapshots = session.query(Snapshot).join(snapshots.subquery()) + snapshots = snapshots.all() + return snapshots
+ +
[docs] def delete(self): + session = object_session(self) + if self.table_name is not None: + table_reference_count = ( + session.query(Version) + .filter(Version.table_name == self.table_name) + .count() + ) + if table_reference_count <= 1: + session.execute( + DropTable(Table(self.table_name, MetaData()), if_exists=True) + ) + session.delete(self)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/subprocess.html b/_modules/koapy/utils/subprocess.html new file mode 100644 index 00000000..eaff76ff --- /dev/null +++ b/_modules/koapy/utils/subprocess.html @@ -0,0 +1,294 @@ + + + + + + + + koapy.utils.subprocess — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.subprocess

+import inspect
+import subprocess
+import sys
+import textwrap
+
+from koapy.utils.logging import get_logger
+
+
[docs]logger = get_logger(__name__)
+ + +
[docs]def function_to_script(func): + function_sig = inspect.signature(func) + assert all( + p.default != p.empty for p in function_sig.parameters + ), "Function should not require any parameters" + + function_name = func.__name__ + function_impl = inspect.getsource(func) + function_impl = textwrap.dedent(function_impl) + + script = ( + textwrap.dedent( + """ + %s + + if __name__ == '__main__': + %s() + """ + ) + % (function_impl, function_name) + ) + + return script
+ + +
[docs]def function_to_subprocess_args(func, executable=None): + if executable is None: + executable = sys.executable + script = function_to_script(func) + args = [executable, "-c", script] + return args
+ + +
[docs]def run_file(filename, *args, executable=None, **kwargs): + if executable is None: + executable = sys.executable + cmd = [executable, filename] + return subprocess.check_call(cmd, *args, **kwargs)
+ + +
[docs]def run_script(script, *args, executable=None, **kwargs): + if executable is None: + executable = sys.executable + cmd = [executable, "-c", script] + return subprocess.check_call(cmd, *args, **kwargs)
+ + +
[docs]def run_function(function, *args, executable=None, **kwargs): + script = function_to_script(function) + return run_script(script, *args, executable=executable, **kwargs)
+ + +
[docs]def quote(s): + return '"' + s.replace('"', '`"') + '"'
+ + +
[docs]def run_as_admin(cmd, cwd=None, check=True, wait=True): + import win32con + import win32event + import win32process + + # pyright: reportMissingImports=false + # pylint: disable=import-error,no-name-in-module + from win32com.shell import shellcon + from win32com.shell.shell import ShellExecuteEx + + kwargs = dict( + nShow=win32con.SW_SHOWNORMAL, + fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, + lpVerb="runas", + lpFile=cmd[0], + lpParameters=" ".join(cmd[1:]), + ) + + if cwd is not None: + kwargs["lpDirectory"] = cwd + + logger.info("Running command: %s", " ".join(cmd)) + procInfo = ShellExecuteEx(**kwargs) + + if check or wait: + procHandle = procInfo["hProcess"] + _ = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) + rc = win32process.GetExitCodeProcess(procHandle) + logger.info("Process handle %s returned code %d", procHandle, rc) + if check and rc < 0: + raise subprocess.CalledProcessError(rc, cmd) + else: + rc = None + + return rc
+ + +
[docs]def create_job_object_for_cleanup(): + # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s + import win32job + + jobAttributes = None + jobName = "" + hJob = win32job.CreateJobObject(jobAttributes, jobName) + extendedInfo = win32job.QueryInformationJobObject( + hJob, win32job.JobObjectExtendedLimitInformation + ) + basicLimitInformation = extendedInfo["BasicLimitInformation"] + basicLimitInformation["LimitFlags"] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE + win32job.SetInformationJobObject( + hJob, + win32job.JobObjectExtendedLimitInformation, + extendedInfo, + ) + return hJob
+ + +
[docs]job_handle = create_job_object_for_cleanup()
+ + +
[docs]def make_process_die_when_parent_dies(pid): + assert pid != 0 + + # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s + import win32api + import win32con + import win32job + + desiredAccess = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA + inheritHandle = False + hProcess = win32api.OpenProcess( + desiredAccess, + inheritHandle, + pid, + ) + # process will be terminated when job is destroyed + # job will be destroyed when its last handle is closed + # job handle will be closed when it loses its reference, hJob in this case + hJob = job_handle + win32job.AssignProcessToJobObject(hJob, hProcess)
+ + +
[docs]class Popen(subprocess.Popen): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + make_process_die_when_parent_dies(self.pid)
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/_modules/koapy/utils/threading.html b/_modules/koapy/utils/threading.html new file mode 100644 index 00000000..c6e0922d --- /dev/null +++ b/_modules/koapy/utils/threading.html @@ -0,0 +1,161 @@ + + + + + + + + koapy.utils.threading — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Source code for koapy.utils.threading

+import threading
+
+
+
[docs]class Singleton: + + _instance = None + _lock = threading.RLock() + + @classmethod + def _get_instance_without_check(cls, *args, **kwargs): + return cls._instance + + @classmethod +
[docs] def get_instance(cls, *args, **kwargs): + with cls._lock: + if not isinstance(cls._instance, cls): + cls._instance = cls(*args, **kwargs) + cls.get_instance = cls._get_instance_without_check + return cls._instance
+
+ +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/docs/source/authors.rst b/_sources/authors.rst similarity index 100% rename from docs/source/authors.rst rename to _sources/authors.rst diff --git a/_sources/autoapi/index.rst b/_sources/autoapi/index.rst new file mode 100644 index 00000000..94c54c1e --- /dev/null +++ b/_sources/autoapi/index.rst @@ -0,0 +1,11 @@ +API Reference +============= + +This page contains auto-generated API reference documentation [#f1]_. + +.. toctree:: + :titlesonly: + + /autoapi/koapy/index + +.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.rst new file mode 100644 index 00000000..e5bcd363 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.rst @@ -0,0 +1,34 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint` +=================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusDispatch + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusIncompleteProgID + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusEntrypoint + + + + +.. py:class:: CybosPlusDispatch(entrypoint, progid) + + +.. py:class:: CybosPlusIncompleteProgID(entrypoint, prefix) + + +.. py:class:: CybosPlusEntrypoint + + Bases: :py:obj:`koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin` + + http://cybosplus.github.io/ + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.rst new file mode 100644 index 00000000..1599b824 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.rst @@ -0,0 +1,86 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin` +======================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin + + + + +.. py:class:: CybosPlusEntrypointMixin + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: GetConnectState(self) + + + .. py:method:: ConnectUsingPywinauto_Impl(cls, credentials=None) + :classmethod: + + https://github.com/ippoeyeslhw/cppy/blob/master/cp_luncher.py + + + .. py:method:: ConnectUsingPywinauto_RunScriptInSubprocess(cls, credentials=None) + :classmethod: + + + .. py:method:: ConnectUsingPywinauto(self, credentials=None) + + + .. py:method:: Connect(self, credentials=None) + + + .. py:method:: CommConnect(self, credentials=None) + + + .. py:method:: EnsureConnected(self, credentials=None) + + + .. py:method:: GetCodeListByMarketAsList(self, market) + + 0: 구분없음 + 1: 거래소 + 2: 코스닥 + 3: 프리보드 + 4: KRX + + + .. py:method:: GetKospiCodeList(self) + + + .. py:method:: GetKosdaqCodeList(self) + + + .. py:method:: GetGeneralCodeList(self, include_preferred_stock=False, include_etn=False, include_etf=False, include_mutual_fund=False, include_reits=False, include_kosdaq=False) + + + .. py:method:: GetStockDataAsDataFrame(self, code, chart_type, interval, start_date=None, end_date=None, adjusted_price=False, adjustement_only=False) + + http://cybosplus.github.io/cpsysdib_rtf_1_/stockchart.htm + + + .. py:method:: GetDailyStockDataAsDataFrame(self, code, start_date=None, end_date=None, adjusted_price=False) + + + .. py:method:: GetMinuteStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, adjusted_price=False) + + + .. py:method:: GetDailyAdjustmentRatioAsDataFrame(self, code, start_date=None, end_date=None) + + + .. py:method:: GetCurrentStockDataAsDataFrame(self, codes) + + http://cybosplus.github.io/cpdib_rtf_1_/stockmst2.htm + + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.rst new file mode 100644 index 00000000..e7af86e2 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.rst @@ -0,0 +1,53 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.core.CybosPlusError` +============================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.core.CybosPlusError + + +Module Contents +--------------- + +.. py:exception:: CybosPlusError + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + +.. py:exception:: CybosPlusRequestError(code, message=None) + + Bases: :py:obj:`CybosPlusError` + + 아래 문서에서 [BlockRequest/Blockrequest2/Request의 리턴값] 내용 참조 + http://cybosplus.github.io/cputil_rtf_1_/cybosplus_interface.htm + + .. py:attribute:: ERROR_MESSAGE_BY_CODE + + + + + .. py:method:: get_error_message_by_code(cls, code, default=None) + :classmethod: + + + .. py:method:: check_code_or_raise(cls, code) + :classmethod: + + + .. py:method:: wrap_to_check_code_or_raise(cls, func) + :classmethod: + + + .. py:method:: try_or_raise(cls, arg) + :classmethod: + + + .. py:method:: code(self) + :property: + + + .. py:method:: message(self) + :property: + + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.rst new file mode 100644 index 00000000..5aed88ed --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.rst @@ -0,0 +1,40 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter` +==================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter.CybosPlusLookupRequestRateLimiter + koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter.CybosPlusTradeRequestRateLimiter + + + + +.. py:class:: CybosPlusLookupRequestRateLimiter + + Bases: :py:obj:`koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter` + + 시세 오브젝트 조회 제한: 15초에 최대 60건으로제한 + + Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. + http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640 + + +.. py:class:: CybosPlusTradeRequestRateLimiter + + Bases: :py:obj:`koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter` + + 주문관련 오브젝트 조회 제한: 15초에 최대 20건으로제한 + + Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. + http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640 + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/index.rst new file mode 100644 index 00000000..9c891abe --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/core/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.core` +=============================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.core + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + CybosPlusEntrypoint/index.rst + CybosPlusEntrypointMixin/index.rst + CybosPlusError/index.rst + CybosPlusRateLimiter/index.rst + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/index.rst new file mode 100644 index 00000000..63853179 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/index.rst @@ -0,0 +1,16 @@ +:py:mod:`koapy.backend.daishin_cybos_plus` +========================================== + +.. py:module:: koapy.backend.daishin_cybos_plus + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + core/index.rst + proxy/index.rst + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.rst new file mode 100644 index 00000000..7ff961aa --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.rst @@ -0,0 +1,38 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy` +========================================================================= + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusDispatchProxyMethod + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusDispatchProxy + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusIncompleteProgIDProxy + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusEntrypointProxy + + + + +.. py:class:: CybosPlusDispatchProxyMethod(proxy, name) + + +.. py:class:: CybosPlusDispatchProxy(proxy, progid) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + +.. py:class:: CybosPlusIncompleteProgIDProxy(proxy, prefix) + + +.. py:class:: CybosPlusEntrypointProxy(host=None, port=None) + + Bases: :py:obj:`koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin` + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.rst new file mode 100644 index 00000000..0746c84a --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.rst @@ -0,0 +1,33 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService` +====================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService.CybosPlusProxyService + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService.main + + + +.. py:class:: CybosPlusProxyService(host=None, port=None, max_workers=None) + + +.. py:function:: main() + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.rst new file mode 100644 index 00000000..efaee07e --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils` +================================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.AssignPrimitive + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.ExtractPrimitive + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.Protoc + + + +.. py:function:: AssignPrimitive(message, value) + + +.. py:function:: ExtractPrimitive(message) + + +.. py:function:: Protoc() + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.rst new file mode 100644 index 00000000..d7d051ef --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.rst @@ -0,0 +1,70 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer` +============================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEvent + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventIterator + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventHandler + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusProxyServiceServicer + + + + +.. py:class:: CybosPlusEvent(iterator) + + .. py:method:: done(self) + + + .. py:method:: wait_for_done(self) + + + +.. py:class:: CybosPlusEventIterator(handler) + + .. py:method:: notify(self) + + + +.. py:class:: CybosPlusEventHandler + + .. py:method:: OnRecieved(self) + + + +.. py:class:: CybosPlusProxyServiceServicer + + Bases: :py:obj:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer` + + Missing associated documentation comment in .proto file. + + .. py:method:: Dispatch(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Property(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Method(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Event(self, request_iterator, context) + + Missing associated documentation comment in .proto file. + + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.rst new file mode 100644 index 00000000..cd29d386 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.rst @@ -0,0 +1,204 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2` +========================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2 + +.. autoapi-nested-parse:: + + Generated protocol buffer code. + + + +Module Contents +--------------- + +.. py:data:: DESCRIPTOR + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: DispatchRequest + + + + +.. py:data:: DispatchResponse + + + + +.. py:data:: PropertyRequest + + + + +.. py:data:: PrimitiveValueArray + + + + +.. py:data:: PrimitiveValue + + + + +.. py:data:: PropertyResponse + + + + +.. py:data:: Argument + + + + +.. py:data:: MethodRequest + + + + +.. py:data:: MethodResponse + + + + +.. py:data:: EventStartRequest + + + + +.. py:data:: EventDoneRequest + + + + +.. py:data:: EventStopRequest + + + + +.. py:data:: EventRequest + + + + +.. py:data:: EventStartedResponse + + + + +.. py:data:: EventFiredResponse + + + + +.. py:data:: EventResponse + + + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.rst new file mode 100644 index 00000000..92319f55 --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.rst @@ -0,0 +1,94 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc` +=============================================================================== + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc + +.. autoapi-nested-parse:: + + Client and server classes corresponding to protobuf-defined services. + + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceStub + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyService + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.add_CybosPlusProxyServiceServicer_to_server + + + +.. py:class:: CybosPlusProxyServiceStub(channel) + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + +.. py:class:: CybosPlusProxyServiceServicer + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + .. py:method:: Dispatch(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Property(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Method(self, request, context) + + Missing associated documentation comment in .proto file. + + + .. py:method:: Event(self, request_iterator, context) + + Missing associated documentation comment in .proto file. + + + +.. py:function:: add_CybosPlusProxyServiceServicer_to_server(servicer, server) + + +.. py:class:: CybosPlusProxyService + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + .. py:method:: Dispatch(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: Property(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: Method(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: Event(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + diff --git a/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.rst b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.rst new file mode 100644 index 00000000..4f1b767f --- /dev/null +++ b/_sources/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.rst @@ -0,0 +1,20 @@ +:py:mod:`koapy.backend.daishin_cybos_plus.proxy` +================================================ + +.. py:module:: koapy.backend.daishin_cybos_plus.proxy + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + CybosPlusEntrypointProxy/index.rst + CybosPlusProxyService/index.rst + CybosPlusProxyServiceMessageUtils/index.rst + CybosPlusProxyServiceServicer/index.rst + CybosPlusProxyService_pb2/index.rst + CybosPlusProxyService_pb2_grpc/index.rst + + diff --git a/_sources/autoapi/koapy/backend/index.rst b/_sources/autoapi/koapy/backend/index.rst new file mode 100644 index 00000000..fc4dc0d2 --- /dev/null +++ b/_sources/autoapi/koapy/backend/index.rst @@ -0,0 +1,17 @@ +:py:mod:`koapy.backend` +======================= + +.. py:module:: koapy.backend + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + daishin_cybos_plus/index.rst + kiwoom_open_api_plus/index.rst + kiwoom_open_api_w/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.rst new file mode 100644 index 00000000..af3d394b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.rst @@ -0,0 +1,34 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition` +============================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionEntry + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionFile + + + + +.. py:class:: KiwoomOpenApiPlusConditionEntry(header, item_id, group_id, group_name, group_tp, name, group_id_small, order_no, type_position, upjong, portfolio, recommend, acc, group, excepts, month, exp, count, rules) + + .. py:method:: from_datfile(cls, f: TextIO) + :classmethod: + + + +.. py:class:: KiwoomOpenApiPlusConditionFile(version: str, entries: Sequence[KiwoomOpenApiPlusConditionEntry]) + + .. py:method:: from_datfile(cls, f: Union[str, os.PathLike, TextIO], encoding: Optional[str] = None) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.rst new file mode 100644 index 00000000..44117e51 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.rst @@ -0,0 +1,1217 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions` +==================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions + + + + +.. py:class:: KiwoomOpenApiPlusDispatchFunctions + + .. py:method:: CommConnect(self) -> int + + 로그인 윈도우를 실행한다. + + 수동 로그인 설정인 경우 로그인창을 출력. + 자동 로그인 설정인 경우 로그인창에서 자동으로 로그인을 시도합니다. + + 로그인이 성공하거나 실패하는 경우 OnEventConnect() 이벤트가 발생하고 이벤트의 + 인자 값으로 로그인 성공 여부를 알 수 있다. + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: CommTerminate(self) -> None + + 더 이상 지원하지 않는 함수. + + 프로그램 종료없이 서버와의 접속만 단절시키는 함수입니다. + ※ 함수 사용 후 사용자의 오해소지가 생기는 이유로 더 이상 사용할 수 없는 함수입니다. + + 통신 연결 상태는 GetConnectState() 메소드로 알 수 있다. + + + .. py:method:: CommRqData(self, sRQName: str, sTrCode: str, nPrevNext: int, sScreenNo: str) -> int + + 통신 데이터를 서버로 전송한다. + + 반환 코드 구분: + - OP_ERR_NONE(0): 정상처리 + - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 + - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 + - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 + + :param sRQName: 사용자 구분명 (임의로 지정, 한글 지원) + :type sRQName: str + :param sTrCode: 조회하려는 TR 코드 + :type sTrCode: str + :param nPrevNext: 연속조회 여부 (0:조회, 2:연속) + :type nPrevNext: int + :param sScreenNo: 화면번호 (4자리 숫자 임의로 지정) + :type sScreenNo: str + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: GetLoginInfo(self, sTag: str) -> str + + 로그인한 사용자 정보를 반환한다. + + 태그값 구분: + - "ACCOUNT_CNT": 전체 보유계좌 개수를 반환합니다. + - "ACCLIST" 또는 "ACCNO": 구분자 ';' 로 연결된 전체 보유계좌 목록을 반환합니다. + - "USER_ID": 사용자 ID를 반환합니다. + - "USER_NAME": 사용자 이름을 반환합니다. + - "KEY_BSECGB": 키보드 보안 해지 여부를 반환합니다. (0:정상, 1:해지) + - "FIREW_SECGB": 방화벽 설정 여부를 반환합니다. (0:미설정, 1:설정, 2:해지) + - "GetServerGubun": 접속서버 구분을 반환합니다. (1:모의투자, 나머지:실거래서버) + + :param sTag: 사용자 정보 구분 태그 값 + :type sTag: str + + :returns: 태그값에 따른 데이터 반환 + :rtype: str + + + .. py:method:: SendOrder(self, sRQName: str, sScreenNo: str, sAccNo: str, nOrderType: int, sCode: str, nQty: int, nPrice: int, sHogaGb: str, sOrgOrderNo: str) -> int + + 주식 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 9개 인자값을 가진 주식주문 함수이며 리턴값이 0이면 성공이며 나머지는 에러입니다. + 1초에 5회만 주문가능하며 그 이상 주문요청하면 에러 -308을 리턴합니다. + + ※ 시장가, 최유리지정가, 최우선지정가, 시장가IOC, 최유리IOC, 시장가FOK, 최유리FOK, 장전시간외, 장후시간외 주문시 주문가격은 0으로 입력합니다. + ※ 취소 주문일때 주문가격은 0으로 입력합니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 정규장 외 주문: + - 장전 동시호가 주문 + - 08:30 ~ 09:00. 거래구분 00:지정가/03:시장가 (일반주문처럼) + - ※ 08:20 ~ 08:30 시간의 주문은 키움에서 대기하여 08:30 에 순서대로 거래소로 전송합니다. + - 장전시간외 종가 + - 08:30 ~ 08:40. 거래구분 61:장전시간외종가. 가격 0입력 + - ※ 전일 종가로 거래. 미체결시 자동취소되지 않음 + - 장마감 동시호가 주문 + - 15:20 ~ 15:30. 거래구분 00:지정가/03:시장가 (일반주문처럼) + - 장후 시간외 종가 + - 15:40 ~ 16:00. 거래구분 81:장후시간외종가. 가격 0입력 + - ※ 당일 종가로 거래 + - 시간외 단일가 + - 16:00 ~ 18:00. 거래구분 62:시간외단일가. 가격 입력 + - ※ 10분 단위로 체결, 당일 종가대비 +-10% 가격으로 거래 + + 주문 유형: + - 1: 신규매수 + - 2: 신규매도 + - 3: 매수취소 + - 4: 매도취소 + - 5: 매수정정 + - 6: 매도정정 + + :param sRQName: 사용자 구분 요청명 + :type sRQName: str + :param sScreenNo: 화면번호 (4자리) + :type sScreenNo: str + :param sAccNo: 계좌번호 (10자리) + :type sAccNo: str + :param nOrderType: 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + :type nOrderType: int + :param sCode: 종목코드 (6자리) + :type sCode: str + :param nQty: 주문수량 + :type nQty: int + :param nPrice: 주문단가 + :type nPrice: int + :param sHogaGb: 거래구분 (혹은 호가구분) + :type sHogaGb: str + :param sOrgOrderNo: 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. + :type sOrgOrderNo: str + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: SendOrderFO(self, sRQName: str, sScreenNo: str, sAccNo: str, sCode: str, lOrdKind: int, sSlbyTp: str, sOrdTp: str, lQty: int, sPrice: str, sOrgOrdNo: str) -> int + + 선물/옵션 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 코스피지수200 선물옵션 전용 주문함수입니다. + + 거래 구분: + - 1: 지정가 + - 2: 조건부지정가 + - 3: 시장가 + - 4: 최유리지정가 + - 5: 지정가(IOC) + - 6: 지정가(FOK) + - 7: 시장가(IOC) + - 8: 시장가(FOK) + - 9: 최유리지정가(IOC) + - A: 최유리지정가(FOK) + + ※ 장종료 후 시간외 주문은 지정가 선택 + + :param sRQName: 사용자 구분명 + :type sRQName: str + :param sScreenNo: 화면번호 + :type sScreenNo: str + :param sAccNo: 계좌번호 (10자리) + :type sAccNo: str + :param sCode: 종목코드 + :type sCode: str + :param lOrdKind: 주문종류 (1:신규매매, 2:정정, 3:취소) + :type lOrdKind: int + :param sSlbyTp: 매매구분 (1:매도, 2:매수) + :type sSlbyTp: str + :param sOrdTp: 거래구분 + :type sOrdTp: str + :param lQty: 주문수량 + :type lQty: int + :param sPrice: 주문가격 + :type sPrice: str + :param sOrgOrdNo: 원주문번호 + :type sOrgOrdNo: str + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: SetInputValue(self, sID: str, sValue: str) -> None + + TR 입력 값을 서버통신 전에 입력한다. + + 조회요청시 TR의 Input값을 지정하는 함수입니다. + CommRqData() 호출 전에 입력값들을 셋팅합니다. + 각 TR마다 Input 항목이 다릅니다. 순서에 맞게 Input 값들을 셋팅해야 합니다. + + :param sID: TR에 명시된 Input 이름 + :type sID: str + :param sValue: Input 이름으로 지정한 값 + :type sValue: str + + + .. py:method:: SetOutputFID(self, sID: str) -> int + + 1.0.0.1 버전 이후 사용하지 않음. + + + .. py:method:: CommGetData(self, sJongmokCode: str, sRealType: str, sFieldName: str, nIndex: int, sInnerFieldName: str) -> str + + 이 함수는 지원하지 않을 것이므로 용도에 맞는 전용 함수를 사용할 것. (비고참고) + + 일부 TR에서 사용상 제약이 있으므로 이 함수 대신 GetCommData() 함수를 사용하시기 바랍니다. + + 비고: + - 조회 정보 요청: GetCommData(strTrCode: str, strRecordName: str, nIndex: int, strItemName: str) + - 실시간 정보 요청: GetCommRealData(sTrCode: str, nFid: int) + - 체결 정보 요청: GetChejanData(nFid: int) + + + .. py:method:: DisconnectRealData(self, sScnNo: str) -> None + + 화면 내 모든 리얼데이터 요청을 제거한다. + + 시세데이터를 요청할때 사용된 화면번호를 이용하여 + 해당 화면번호로 등록되어져 있는 종목의 실시간시세를 서버에 등록해지 요청합니다. + 이후 해당 종목의 실시간시세는 수신되지 않습니다. + 단, 해당 종목이 또다른 화면번호로 실시간 등록되어 있는 경우 해당종목에대한 실시간시세 데이터는 계속 수신됩니다. + + 화면을 종료할 때 반드시 위 함수를 호출해야 한다. + + :param sScnNo: 화면번호 (4자리) + + + .. py:method:: GetRepeatCnt(self, sTrCode: str, sRecordName: str) -> int + + 레코드 반복횟수를 반환한다. + + 데이터 수신시 멀티데이터의 갯수(반복수)를 얻을수 있습니다. + 예를 들어 차트조회는 한번에 최대 900개 데이터를 수신할 수 있는데 + 이렇게 수신한 데이터갯수를 얻을때 사용합니다. + 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + + :param sTrCode: TR 이름 + :type sTrCode: str + :param sRecordName: 레코드 이름 + :type sRecordName: str + + :returns: 레코드의 반복횟수 + :rtype: int + + + .. py:method:: CommKwRqData(self, sArrCode: str, bNext: int, nCodeCount: int, nTypeFlag: int, sRQName: str, sScreenNo: str) -> int + + 복수종목조회 요청을 서버로 송신한다. + + 한번에 100종목까지 조회할 수 있는 복수종목 조회함수 입니다. + 함수인자로 사용하는 종목코드 리스트는 조회하려는 종목코드 사이에 구분자 ';' 를 추가해서 만들면 됩니다. + 수신되는 데이터는 TR목록에서 복수종목정보요청(OPTKWFID) Output을 참고하시면 됩니다. + + ※ OPTKWFID TR은 CommKwRqData() 함수 전용으로, CommRqData 로는 사용할 수 없습니다. + ※ OPTKWFID TR은 영웅문4 HTS의 관심종목과는 무관합니다. + + 반환 코드 구분: + - OP_ERR_NONE(0): 정상처리 + - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 + - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 + - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 + + :param sArrCode: 종목리스트 + :type sArrCode: str + :param bNext: 연속조회 여부 (0:기본값, 1:연속조회(지원안함)) + :type bNext: int + :param nCodeCount: 종목개수 + :type nCodeCount: int + :param nTypeFlag: 조회구분 (0:주식 종목, 3:선물옵션 종목) + :type nTypeFlag: int + :param sRQName: 사용자 구분명 + :type sRQName: str + :param sScreenNo: 화면번호 (4자리) + :type sScreenNo: str + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: GetAPIModulePath(self) -> str + + OpenAPI 모듈의 경로를 반환한다. + + :returns: OpenAPI 모듈의 설치 경로 + :rtype: str + + + .. py:method:: GetCodeListByMarket(self, sMarket: str) -> str + + 시장구분에 따른 종목코드를 반환한다. + + 주식 시장별 종목코드 리스트를 ';' 로 구분해서 전달합니다. + 시장구분값을 "" 공백으로 하면 전체시장 코드리스트를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 시장 구분: + - 0: 장내 + - 3: ELW + - 4: 뮤추얼펀드 + - 5: 신주인수권 + - 6: 리츠 + - 8: ETF + - 9: 하이일드펀드 + - 10: 코스닥 + - 30: K-OTC + - 50: 코넥스 (KONEX) + + :param sMarket: 시장 구분값 + :type sMarket: str + + :returns: 종목코드 리스트, 종목간 구분은 ';' 이다. + :rtype: str + + + .. py:method:: GetConnectState(self) -> int + + 현재 접속상태를 반환한다. + + 서버와 현재 접속 상태를 알려줍니다. + + :returns: 접속상태, 1:연결, 0:연결안됨 + :rtype: int + + + .. py:method:: GetMasterCodeName(self, sTrCode: str) -> str + + 종목코드의 한글명을 반환한다. + + 종목코드에 해당하는 종목명을 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 장내외, 지수선옵, 주식선옵 검색 가능. + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 종목 한글명 + :rtype: str + + + .. py:method:: GetMasterListedStockCnt(self, sTrCode: str) -> int + + 종목코드의 상장주식수를 반환한다. + + 입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 상장주식수 + :rtype: int + + + .. py:method:: GetMasterConstruction(self, sTrCode: str) -> str + + 종목코드의 감리구분을 반환한다. + + 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. + (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 감리 구분: + - 정상 + - 투자주의 + - 투자경고 + - 투자위험 + - 투자주의환기종목 + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 감리구분 (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + :rtype: str + + + .. py:method:: GetMasterListedStockDate(self, sTrCode: str) -> str + + 종목코드의 상장일을 반환한다. + + 입력한 종목의 상장일을 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 상장일 (8자리, YYYYMMDD) + :rtype: str + + + .. py:method:: GetMasterLastPrice(self, sTrCode: str) -> str + + 종목코드의 전일가를 반환한다. + + 입력한 종목의 당일 기준가를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 전일가 + :rtype: str + + + .. py:method:: GetMasterStockState(self, sTrCode: str) -> str + + 종목코드의 종목상태를 반환한다. + + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + :param sTrCode: 종목코드 (4자리) + :type sTrCode: str + + :returns: 종목상태 (정상, 증거금N%, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능) + :rtype: str + + + .. py:method:: GetDataCount(self, strRecordName: str) -> int + + 레코드의 반복개수를 반환한다. + + ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 + 해당 함수 대신 GetRepeatCnt() 를 사용하는게 더 바람직할 듯 + + :param strRecordName: 레코드 명 + :type strRecordName: str + + :returns: 레코드 반복개수 + :rtype: str + + + .. py:method:: GetOutputValue(self, strRecordName: str, nRepeatIdx: int, nItemIdx: int) -> str + + 레코드의 반복순서와 아이템의 출력순서에 따라 수신데이터를 반환한다. + + ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 + 해당 함수 대신 GetCommData() 를 사용하는게 더 바람직할 듯 + + :param strRecordName: 레코드 명 + :type strRecordName: str + :param nRepeatIdx: 반복 순서 + :type nRepeatIdx: int + :param nItemIdx: 아이템 순서 + :type nItemIdx: int + + :returns: 수신 데이터 + :rtype: str + + + .. py:method:: GetCommData(self, strTrCode: str, strRecordName: str, nIndex: int, strItemName: str) -> str + + 수신 데이터를 반환한다. + + OnReceiveTRData() 이벤트가 발생될때 수신한 데이터를 얻어오는 함수입니다. + 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + + :param strTrCode: TR코드 + :type strTrCode: str + :param strRecordName: 레코드명 + :type strRecordName: str + :param nIndex: 복수데이터 인덱스 + :type nIndex: int + :param strItemName: 아이템명 (TR별 출력항목 이름) + :type strItemName: str + + :returns: 수신 데이터 + :rtype: str + + + .. py:method:: GetCommRealData(self, sTrCode: str, nFid: int) -> str + + 실시간 시세 데이터를 반환한다. + + 실시간시세 데이터 수신 이벤트인 OnReceiveRealData() 가 발생될때 실시간데이터를 얻어오는 함수입니다. + 이 함수는 OnReceiveRealData() 이벤트가 발생될때 그 안에서 사용해야 합니다. + FID 값은 KOAStudio 의 "실시간목록" 탭에서 확인할 수 있습니다. + + 일반적으로 strTrCode 는 OnReceiveRealData() 이벤트 함수의 첫번째 매개변수를 사용한다. + + :param strTrCode: TR코드 + :type strTrCode: str + :param nFid: 실시간 아이템 + :type nFid: int + + :returns: 수신 데이터 + :rtype: str + + + .. py:method:: GetChejanData(self, nFid: int) -> str + + 체결잔고 데이터를 반환한다. + + OnReceiveChejan() 이벤트가 발생될때 FID 에 해당되는 값을 구하는 함수입니다. + 이 함수는 OnReceiveChejan() 이벤트 안에서 사용해야 합니다. + Ex) 체결가 = GetChejanData(910) + + :param nFid: 체결잔고 아이템 + :type nFid: int + + :returns: 수신 데이터 + :rtype: str + + + .. py:method:: GetThemeGroupList(self, nType: int) -> str + + 테마코드와 테마명을 반환한다. + + 반환값의 코드와 코드명 구분은 '|', 코드의 구분은 ';' + Ex) 100|태양광_폴리실리콘;152|합성섬유 + + :param nType: 정렬순서 (0:코드순, 1:테마순) + :type nType: int + + :returns: 코드와 코드명 리스트 + :rtype: str + + + .. py:method:: GetThemeGroupCode(self, strThemeCode: str) -> str + + 테마코드에 소속된 종목코드를 반환한다. + + 반환값의 종목코드간 구분은 ';' + Ex) A000660;A005930 + + :param strThemeCode: 테마코드 + :type strThemeCode: str + + :returns: 종목코드 리스트 + :rtype: str + + + .. py:method:: GetFutureList(self) -> str + + 지수선물 리스트를 반환한다. + + 지수선물 종목코드 리스트를 ';'로 구분해서 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 반환값의 종목코드간 구분은 ';' + Ex) 101J9000;101JC000 + + :returns: 종목코드 리스트 + :rtype: str + + + .. py:method:: GetFutureCodeByIndex(self, nIndex: int) -> str + + 지수선물 코드를 반환한다. + + Ex) 최근월선물 = GetFutureCodeByIndex(0) + 최근월스프레드 = GetFutureCodeByIndex(4) + + :param nIndex: 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드 + :type nIndex: int + + :returns: 종목코드 + :rtype: str + + + .. py:method:: GetActPriceList(self) -> str + + 지수옵션 행사가 리스트를 반환한다. + + 지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ';' 로 구분해서 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + ※ PDF 문서상의 예시에서는 소수점 아래가 존재하는 예시지만, KOAStudio 의 설명과 예시에서는 그렇지 않음. + 아마도 KOAStudio 의 설명을 따르는게 더 바람직할 듯. + + :returns: 행사가 + :rtype: str + + + .. py:method:: GetMonthList(self) -> str + + 지수옵션 월물 리스트를 반환한다. + + 지수옵션 월물정보를 ';' 로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + 반환값의 월물간 구분은 ';' + Ex) 201412;201409;201408;201407;201407;201408;201409;201412 + + :returns: 월물 (YYYYMM;YYYYMM;...) + :rtype: str + + + .. py:method:: GetOptionCode(self, strActPrice: str, nCp: int, strMonth: str) -> str + + 행사가와 월물 콜풋으로 종목코드를 구한다. + + 인자로 지정한 지수옵션 코드를 전달합니다. + + 로그인 한 후에 사용할 수 있는 함수입니다. + + :param strActPrice: 행사가 (소수점 포함) + :type strActPrice: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param strMonth: 월물 (6자리, YYYYMM) + :type strMonth: str + + :returns: 종목코드 + :rtype: str + + .. rubric:: Examples + + >>> GetOptionCode("260.00", 2, "201407") + + + .. py:method:: GetOptionCodeByMonth(self, sTrCode: str, nCp: int, strMonth: str) -> str + + 입력된 종목코드와 동일한 행사가의 코드중 입력한 월물의 코드를 구한다. + + :param sTrCode: 종목코드 + :type sTrCode: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param strMonth: 월물 (6자리, YYYYMM) + :type strMonth: str + + :returns: 종목코드 + :rtype: str + + .. rubric:: Examples + + >>> GetOptionCodeByMonth("201J7260", 2, "201412") + "201JC260" + + + .. py:method:: GetOptionCodeByActPrice(self, sTrCode: str, nCp: int, nTick: int) -> str + + 입력된 종목코드와 동일한 월물의 코드중 입력한 틱만큼 벌어진 코드를 구한다. + + :param sTrCode: 종목코드 + :type sTrCode: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param nTick: 행사가 틱 + :type nTick: int + + :returns: 종목코드 + :rtype: str + + .. rubric:: Examples + + >>> GetOptionCodeByActPrice("201J7260", 2, -1) + "201J7262" + + + .. py:method:: GetSFutureList(self, strBaseAssetCode: str) -> str + + 주식선물 코드 리스트를 반환한다. + + 출력값의 코드간 구분은 ';' 이다. + + :param strBaseAssetCode: 기초자산코드 + :type strBaseAssetCode: str + + :returns: 종목코드 리스트 + :rtype: str + + + .. py:method:: GetSFutureCodeByIndex(self, strBaseAssetCode: str, nIndex: int) -> str + + 주식선물 코드를 반환한다. + + :param strBaseAssetCode: 기초자산코드 + :type strBaseAssetCode: str + :param nIndex: 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드, 8 ~ 11: 스타 선물, 12 ~ : 스타 스프레드 + :type nIndex: int + + :returns: 종목코드 리스트 + :rtype: str + + .. rubric:: Examples + + >>> GetSFutureCodeByIndex("11", 0) + + + .. py:method:: GetSActPriceList(self, strBaseAssetGb: str) -> str + + 주식옵션 행사가 리스트를 반환한다. + + :param strBaseAssetGb: 기초자산코드구분 + :type strBaseAssetGb: str + + :returns: 행사가 리스트, 행사가간 구분은 ';' + :rtype: str + + .. rubric:: Examples + + >>> GetSActPriceList("11") + + + .. py:method:: GetSMonthList(self, strBaseAssetGb: str) -> str + + 주식옵션 월물 리스트를 반환한다. + + :param strBaseAssetGb: 기초자산코드구분 + :type strBaseAssetGb: str + + :returns: 월물 리스트, 월물간 구분은 ';' + :rtype: str + + .. rubric:: Examples + + >>> GetSMonthList("11") + + + .. py:method:: GetSOptionCode(self, strBaseAssetGb: str, strActPrice: str, nCp: int, strMonth: str) -> str + + 주식옵션 코드를 반환한다. + + :param strBaseAssetGb: 기초자산코드구분 + :type strBaseAssetGb: str + :param strActPrice: 행사가 (소수점 포함) + :type strActPrice: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param strMonth: 월물 (6자리, YYYYMM) + :type strMonth: str + + :returns: 주식옵션 코드 + :rtype: str + + .. rubric:: Examples + + >>> GetSOptionCode("11", "1300000", 2, "1412") + + + .. py:method:: GetSOptionCodeByMonth(self, strBaseAssetGb: str, sTrCode: str, nCp: int, strMonth: str) -> str + + 입력한 주식옵션 코드에서 월물만 변경하여 반환한다. + + :param strBaseAssetGb: 기초자산코드구분 + :type strBaseAssetGb: str + :param sTrCode: 종목코드 + :type sTrCode: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param strMonth: 월물 (6자리, YYYYMM) + :type strMonth: str + + :returns: 주식옵션 코드 + :rtype: str + + .. rubric:: Examples + + >>> GetSOptionCodeByMonth("11", "211J8045", 2, "1412") + + + .. py:method:: GetSOptionCodeByActPrice(self, strBaseAssetGb: str, sTrCode: str, nCp: int, nTick: int) -> str + + 입력한 주식옵션 코드에서 행사가만 변경하여 반환한다. + + :param strBaseAssetGb: 기초자산코드구분 + :type strBaseAssetGb: str + :param sTrCode: 종목코드 + :type sTrCode: str + :param nCp: 콜/풋 구분 (2:콜, 3:풋) + :type nCp: int + :param nTick: 행사가 틱 + :type nTick: int + + :returns: 주식옵션 코드 + :rtype: str + + .. rubric:: Examples + + >>> GetSOptionCodeByActPrice("11", "211J8045", 2, 4); + + + .. py:method:: GetSFOBasisAssetList(self) -> str + + 주식선옵 기초자산코드/종목명을 반환한다. + + :returns: 기초자산코드/종목명, 코드와 종목명 구분은 '|', 코드간 구분은 ';' + :rtype: str + + + .. py:method:: GetOptionATM(self) -> str + + 지수옵션 ATM을 반환한다. + + :returns: ATM + :rtype: str + + + .. py:method:: GetSOptionATM(self, strBaseAssetGb: str) -> str + + 주식옵션 ATM을 반환한다. + + :returns: ATM + :rtype: str + + + .. py:method:: GetBranchCodeName(self) -> str + + 회원사 코드와 이름을 반환합니다. + + :returns: 회원사코드/회원사명, 코드와 이름 구분은 '|', 코드간 구분은 ';' (회원사코드|회원사명;회원사코드|회원사명;...) + :rtype: str + + + .. py:method:: CommInvestRqData(self, sMarketGb: str, sRQName: str, sScreenNo: str) -> int + + 지원하지 않는 함수. + + 시장 구분: + - 001: 코스피 + - 002: 코스닥 + - 003: 선물 + - 004: 콜옵션 + - 005: 풋옵션 + - 006: 스타선물 + - 007: 주식선물 + - 008: 3년국채 + - 009: 5년국채 + - 010: 10년국채 + - 011: 달러선물 + - 012: 엔선물 + - 013: 유로선물 + - 014: 미니금선물 + - 015: 금선물 + - 016: 돈육선물 + - 017: 달러콜옵션 + - 018: 달러풋옵션 + + :param sMarketGb: 시장구분 + :type sMarketGb: str + :param sRQName: 사용자 구분값 + :type sRQName: str + :param sScreenNo: 화면번호 (4자리) + :type sScreenNo: str + + :returns: 통신결과 + :rtype: str + + .. rubric:: Examples + + >>> CommInvestRqData("T00108;T00109", 0, 2, "RQ_1", "0101") + + + .. py:method:: SendOrderCredit(self, sRQName: str, sScreenNo: str, sAccNo: str, nOrderType: int, sCode: str, nQty: int, nPrice: int, sHogaGb: str, sCreditGb: str, sLoanDate: str, sOrgOrderNo: str) -> int + + 신용주식 주문을 서버로 전송한다. + + 서버에 주문을 전송하는 함수 입니다. + 국내주식 신용주문 전용함수입니다. 대주거래는 지원하지 않습니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 신용거래 구분: + - 03: 신용매수 주문 \- 자기융자 + - 대출일은 공백 입력 + - 33: 신용매도 융자상환 주문 \- 자기융자 + - 대출일은 종목별 대출일 입력 + - OPW00005/OPW00004 TR조회로 대출일 조회 + - 99: 신용매도 자기융자 합 + - 대출일은 "99991231" 입력 + - 단, 신용잔고 5개 까지만 융자합 주문 가능 + + 대출일은 YYYYMMDD 형식입니다. + 신용매도 - 자기융자 일때는 종목별 대출일을 입력하고 신용매도 - 융자합이면 "99991231"을 입력합니다. + + :param sRQName: 사용자 구분 요청명 + :type sRQName: str + :param sScreenNo: 화면번호 (4자리) + :type sScreenNo: str + :param sAccNo: 계좌번호 (10자리) + :type sAccNo: str + :param nOrderType: 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + :type nOrderType: int + :param sCode: 종목코드 (6자리) + :type sCode: str + :param nQty: 주문수량 + :type nQty: int + :param nPrice: 주문단가 + :type nPrice: int + :param sHogaGb: 거래구분 + :type sHogaGb: str + :param sCreditGb: 신용구분 + :type sCreditGb: str + :param sLoanDate: 대출일 (8자리, YYYYMMDD) + :type sLoanDate: str + :param sOrgOrderNo: 원주문번호 + :type sOrgOrderNo: str + + :returns: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 + :rtype: int + + + .. py:method:: KOA_Functions(self, sFunctionName: str, sParam: str) -> str + + OpenAPI 기본 기능 이외의 기능들을 제공하는 헬퍼 함수. + + KOA_Function() 함수는 OpenAPI 기본 기능 이외의 기능을 사용하기 쉽도록 만든 함수입니다. + 두 개의 인자값을 사용합니다. + + 기능 목록: + + 1. 계좌 비밀번호 입력창 출력 + + >>> KOA_Functions("ShowAccountWindow", "") + + 2. 접속 서버 확인 (1:모의투자, 나머지:실서버) + + >>> KOA_Functions("GetServerGubun", "") + + 3. 주식종목 시장구분, 종목분류등 정보제공 (구분자는 '|' 와 ';') + 호출결과는 입력한 종목에 대한 대분류, 중분류, 업종구분값을 구분자로 연결한 문자열입니다. + + >>> KOA_Functions("GetMasterStockInfo", "039490") + "시장구분0|거래소;시장구분1|중형주;업종구분|금융업;" + + 4. 조건검색 종목코드와 현재가 수신 (실시간 조건검색은 사용할 수 없음) + 조건검색결과에 종목코드와 그 종목의 현재가를 함께 수신하는 방법이며 실시간 조건검색에서는 사용할 수 없고 오직 조건검색에만 사용할수 있습니다. + + >>> KOA_Functions("SetConditionSearchFlag", "AddPrice") # 현재가 포함하도록 설정 + + 현재가 포함으로 설정시 OnReceiveTrCondition() 이벤트에 "종목코드1^현재가1;종목코드2^현재가2;...종목코드n^현재가n" 형식으로 전달됨. + + >>> KOA_Functions("SetConditionSearchFlag", "DelPrice") # 현재가 미포함 (원래 상태로 전환) + + 현재가 미포함시 기존처럼 "종목코드1^종목코드2...종목코드n" 형식으로 전달므로 설정에 따라 수신데이터 처리방법이 달라져야 하므로 주의하셔야 합니다. + + 5. 업종코드목록 획득 + + >>> KOA_Functions("GetUpjongCode", "0") + + 두번째 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + + 함수반환값은 "시장구분값,업종코드,업종명|시장구분값,업종코드,업종명|...|시장구분값,업종코드,업종명" 형식입니다. + 즉 하나의 업종코드는 입력한 시장구분값과 업종코드 그리고 그 업종명이 쉼표(,)로 구분되며 각 업종코드는 '|'로 구분됩니다. + + 6. 업종이름 획득 + + >>> KOA_Functions("GetUpjongNameByCode", "업종코드입력") + + 7. ETF 투자유의 종목 여부 (2020/09/17 적용) + 거래소 제도개선으로 ETF/ETN 종목 중 투자유의 종목을 매수주문하는 경우 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. + (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) + 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. + + >>> KOA_Functions("IsOrderWarningETF", "종목코드(6자리)") + + 투자유의 종목인 경우 "1" 값이 리턴, 그렇지 않은 경우 "0" 값 리턴. (ETF가 아닌 종목을 입력시 "0" 값 리턴.) + + 8. 주식 전종목대상 투자유의 종목 여부 (2020/11/26 적용) + 거래소 제도개선으로 주식 종목 중 정리매매/단기과열/투자위험/투자경고 종목을 매수주문하는 경우 + 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) + 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. + + >>> KOA_Functions("IsOrderWarningStock", "종목코드(6자리)") + + 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 + + 9. 상장주식수 구하기 (2021/04/08 적용) + 상장주식수를 구하는 GetMasterListedStockCnt() 기존 함수 사용시 특정 종목 데이터가 long 형을 Overflow 하는 현상이 있습니다. + 이에, 상장주식수를 구하는 기능을 신규 추가 합니다. 사용법은 아래와 같습니다. + + >>> KOA_Functions("GetMasterListedStockCntEx", "종목코드(6자리)") + + :param sFunctionName: 함수이름 혹은 기능이름 + :type sFunctionName: str + :param sParam: 함수 매개변수 + :type sParam: str + + :returns: 결과 데이터 + :rtype: str + + + .. py:method:: SetInfoData(self, sInfoData: str) -> int + + 다수의 아이디로 자동로그인이 필요할 때 사용한다. + + :param sInfoData: 아이디 + :type sInfoData: str + + :returns: 통신결과 + :rtype: int + + .. rubric:: Examples + + >>> SetInfoData("UserID") + + + .. py:method:: SetRealReg(self, strScreenNo: str, strCodeList: str, strFidList: str, strOptType: str) -> int + + 실시간 등록을 한다. + + 종목코드와 FID 리스트를 이용해서 실시간 시세를 등록하는 함수입니다. + 한번에 등록가능한 종목과 FID갯수는 100종목, 100개 입니다. + 실시간 등록타입을 0으로 설정하면 등록한 종목들은 실시간 해지되고 등록한 종목만 실시간 시세가 등록됩니다. + 실시간 등록타입을 1로 설정하면 먼저 등록한 종목들과 함께 실시간 시세가 등록됩니다 + + strOptType 이 "0" 으로 하면 같은 화면에서 다른 종목 코드로 실시간 등록을 하게 되면 + 마지막에 사용한 종목코드만 실시간 등록이 되고 기존에 있던 종목은 실시간이 자동 해지됨. + "1" 로 하면 같은 화면에서 다른 종목들을 추가하게 되면 기존에 등록한 종목도 함께 실시간 시세를 받을 수 있음. + 꼭 같은 화면이여야 하고 최초 실시간 등록은 "0" 으로 하고 이후부터 "1" 로 등록해야함. + + :param strScreenNo: 화면번호 (4자리) + :type strScreenNo: str + :param strCodeList: 종목코드 (복수종목가능, ';' 구분자) + :type strCodeList: str + :param strFidList: FID (';' 구분자) + :type strFidList: str + :param strOptType: 등록타입 (0:최초 등록시, 혹은 기존 등록된 종목 해지하고 등록 1:기존 등록된 종목 유지하고 등록) + :type strOptType: str + + :returns: 통신결과 + :rtype: int + + + .. py:method:: GetConditionLoad(self) -> int + + 서버에 저장된 사용자 조건식을 조회해서 임시로 파일에 저장. + + 서버에 저장된 사용자 조건검색 목록을 요청합니다. + 조건검색 목록을 모두 수신하면 OnReceiveConditionVer() 이벤트가 발생됩니다. + 조건검색 목록 요청을 성공하면 1, 아니면 0을 리턴합니다. + + System 폴더에 아이디_NewSaveIndex.dat 파일로 저장된다. OCX 가 종료되면 삭제시킨다. + 조건검색 사용시 이 함수를 최소 한번은 호출해야 조건검색을 할 수 있다. + 영웅문에서 사용자 조건을 수정 및 추가하였을 경우에도 최신의 사용자 조건을 받고 싶으면 다시 + 조회해야한다. + + :returns: 성공하면 1, 아니면 0을 반환 + :rtype: int + + + .. py:method:: GetConditionNameList(self) -> str + + 조건검색 조건명 리스트를 받아온다. + + 서버에서 수신한 사용자 조건식을 조건식의 고유번호와 조건식 이름을 한 쌍으로 하는 문자열들로 전달합니다. + 조건식 하나는 조건식의 고유번호와 조건식 이름이 구분자 '^' 로 나뉘어져 있으며 각 조건식은 ';' 로 나뉘어져 있습니다. + 이 함수는 OnReceiveConditionVer() 이벤트에서 사용해야 합니다. + + :returns: 조건명 리스트 문자열 + :rtype: str + + .. rubric:: Examples + + >>> GetConditionNameList() + "1^내조건식1;2^내조건식2;5^내조건식3;..." + + + .. py:method:: SendCondition(self, strScrNo: str, strConditionName: str, nIndex: int, nSearch: int) -> int + + 조건검색 종목조회TR을 송신한다. + + 서버에 조건검색을 요청하는 함수입니다. + 마지막 인자값으로 조건검색만 할것인지 실시간 조건검색도 수신할 것인지를 지정할 수 있습니다. + GetConditionNameList() 함수로 얻은 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. + 리턴값 1이면 성공이며, 0이면 실패입니다. + 요청한 조건식이 없거나 조건 고유번호와 조건명이 서로 안맞거나 조회횟수를 초과하는 경우 실패하게 됩니다. + + 단순 조건식에 맞는 종목을 조회하기 위해서는 조회구분을 0으로 하고, + 실시간 조건검색을 하기 위해서는 조회구분을 1로 한다. + OnReceiveTrCondition() 으로 결과값이 온다. + 연속조회가 필요한 경우에는 응답받는 곳에서 연속조회 여부에 따라 연속조회를 송신하면된다. + + :param strScrNo: 화면번호 + :type strScrNo: str + :param strConditionName: 조건식 이름 + :type strConditionName: str + :param nIndex: 조건식 인덱스 + :type nIndex: int + :param nSearch: 조회구분 (0:일반조회, 1:실시간조회 (최초 일반조회 + 이후 실시간조회), 2:연속조회) + :type nSearch: int + + :returns: 성공하면 1, 아니면 0을 반환 + :rtype: int + + + .. py:method:: SendConditionStop(self, strScrNo: str, strConditionName: str, nIndex: int) -> None + + 조건검색 실시간 중지TR을 송신한다. + + 실시간 조건검색을 중지할 때 사용하는 함수입니다. + 조건식 조회할때 얻는 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. + + 해당 조건명의 실시간 조건검색을 중지하거나, + 다른 조건명으로 바꿀 때 이전 조건명으로 실시간 조건검색을 반드시 중지해야한다. + 화면 종료시에도 실시간 조건검색을 한 조건명으로 전부 중지해줘야 한다. + + :param strScrNo: 화면번호 + :type strScrNo: str + :param strConditionName: 조건식 이름 + :type strConditionName: str + :param nIndex: 조건식 인덱스 + :type nIndex: int + + :returns: None + + + .. py:method:: GetCommDataEx(self, strTrCode: str, strRecordName: str) + + 차트 조회 데이터를 배열로 받아온다. + + 조회 수신데이터 크기가 큰 차트데이터를 한번에 가져올 목적으로 만든 차트조회 전용함수입니다. + + 조회 데이터가 많은 차트 경우 GetCommData()로 항목당 하나씩 받아오는 것 보다 + 한번에 데이터 전부를 받아서 사용자가 처리할 수 있도록 배열로 받는다. + + ※ Qt 기준으로 QVariant 타입의 배열을 반환하지만 PySide2 에서는 완전히 똑같이 지원하진 않습니다. + + :param strTrCode: TR코드 + :type strTrCode: str + :param strRecordName: 레코드명 + :type strRecordName: str + + :returns: 조회 데이터 배열 + :rtype: QVariant + + + .. py:method:: SetRealRemove(self, strScrNo: str, strDelCode: str) -> None + + 종목별 실시간 해제. + + 실시간시세 해지 함수이며 화면번호와 종목코드를 이용해서 상세하게 설정할 수 있습니다. + + ※ A종목에 대한 실시간이 여러 화면번호로 중복 등록되어 있는 경우 특정 화면번호를 이용한 + SetRealRemove() 함수호출시 A종목의 실시간시세는 해지되지 않습니다. + + SetRealReg() 함수로 실시간 등록한 종목만 실시간 해제 할 수 있다. + + :param strScrNo: 화면번호 (4자리) 또는 "ALL" + :type strScrNo: str + :param strDelCode: 종목코드 또는 "ALL" + :type strDelCode: str + + :returns: None + + + .. py:method:: GetMarketType(self, sTrCode: str) -> int + + 주어진 종목코드의 시장구분값을 가져온다. + + 시장 구분: + - 0: 장내 + - 3: ELW + - 4: 뮤추얼펀드 + - 5: 신주인수권 + - 6: 리츠 + - 8: ETF + - 9: 하이일드펀드 + - 10: 코스닥 + - 30: K-OTC + - 50: 코넥스 (KONEX) + + :param sTrCode: 종목코드 + :type sTrCode: str + + :returns: 시장 구분값 + :rtype: int + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst new file mode 100644 index 00000000..adab42cd --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst @@ -0,0 +1,58 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature` +==================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature.KiwoomOpenApiPlusDispatchSignature + + + + +.. py:class:: KiwoomOpenApiPlusDispatchSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: DISPATCH_SIGNATURES_BY_NAME + :annotation: :Dict[str, KiwoomOpenApiPlusDispatchSignature] + + + + .. py:method:: from_name(cls, name: str) -> KiwoomOpenApiPlusDispatchSignature + :classmethod: + + + .. py:method:: names(cls) -> List[str] + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.rst new file mode 100644 index 00000000..4b1e4ac9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.rst @@ -0,0 +1,101 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable` +================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallableRunnable + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallable + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.P + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.R + + +.. py:data:: P + + + + +.. py:data:: R + + + + +.. py:class:: KiwoomOpenApiPlusDynamicCallableRunnable(future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Sequence[Any]) + + .. py:method:: run(self) + + + .. py:method:: cancel(self) + + + +.. py:class:: KiwoomOpenApiPlusDynamicCallable(control: koapy.compat.pyside2.QtAxContainer.QAxWidget, name: str, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QObject`, :py:obj:`Generic`\ [\ :py:obj:`P`\ , :py:obj:`R`\ ] + + Abstract base class for generic types. + + A generic type is typically declared by inheriting from + this class parameterized with one or more type variables. + For example, a generic mapping type might be defined as:: + + class Mapping(Generic[KT, VT]): + def __getitem__(self, key: KT) -> VT: + ... + # Etc. + + This class can then be used as follows:: + + def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: + try: + return mapping[key] + except KeyError: + return default + + .. py:attribute:: ready_runnable + + + + + .. py:method:: bind_dynamic_call_args(self, *args, **kwargs) -> List[Any] + + + .. py:method:: is_valid_return_type(self, result: Any) -> bool + + + .. py:method:: check_return_value(self, result: Any) + + + .. py:method:: dynamic_call(self, args: Sequence[Any]) -> R + + + .. py:method:: dynamic_call_and_check(self, args: Sequence[Any]) -> R + + + .. py:method:: call(self, *args: P, **kwargs: P) -> R + + + .. py:method:: async_call(self, *args: P, **kwargs: P) -> concurrent.futures.Future + + + .. py:method:: on_ready_runnable(self, runnable: KiwoomOpenApiPlusDynamicCallableRunnable) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.rst new file mode 100644 index 00000000..aa3d5fb9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint` +============================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint.KiwoomOpenApiPlusEntrypoint + + + + +.. py:class:: KiwoomOpenApiPlusEntrypoint(port=None, client_check_timeout=None) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin.KiwoomOpenApiPlusEntrypointMixin`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: get_stub(self) + + + .. py:method:: close_client(self) + + + .. py:method:: close_server_proc(self) + + + .. py:method:: close(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.rst new file mode 100644 index 00000000..326093f6 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin` +================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin.KiwoomOpenApiPlusEntrypointMixin + + + + +.. py:class:: KiwoomOpenApiPlusEntrypointMixin + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.rst new file mode 100644 index 00000000..7a410ebf --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.rst @@ -0,0 +1,472 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError` +======================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError + + +Module Contents +--------------- + +.. py:data:: CallableReturnsInt + + + + +.. py:data:: IntOrBool + + + + +.. py:data:: CallableReturnsIntOrBool + + + + +.. py:data:: IntCompatible + + + + +.. py:data:: BoolCompatible + + + + +.. py:exception:: KiwoomOpenApiPlusError(message: Optional[str] = None) + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + .. py:method:: message(self) + :property: + + + .. py:method:: try_or_raise(cls, arg: IntCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) -> IntCompatible + :classmethod: + + + .. py:method:: try_or_raise_boolean(cls, arg: BoolCompatible, message: str, except_callback: Optional[Callable] = None) -> BoolCompatible + :classmethod: + + + .. py:method:: get_error_message_by_code(cls, code: int, default: Optional[str] = None) + :classmethod: + + + +.. py:exception:: KiwoomOpenApiPlusNegativeReturnCodeError(code: int, message: Optional[str] = None) + + Bases: :py:obj:`KiwoomOpenApiPlusError` + + Common base class for all non-exit exceptions. + + .. py:attribute:: OP_ERR_NONE + :annotation: = 0 + + + + .. py:attribute:: OP_ERR_FAIL + + + + + .. py:attribute:: OP_ERR_COND_NOTFOUND + + + + + .. py:attribute:: OP_ERR_COND_MISMATCH + + + + + .. py:attribute:: OP_ERR_COND_OVERFLOW + + + + + .. py:attribute:: OP_ERR_TR_FAIL + + + + + .. py:attribute:: OP_ERR_LOGIN + + + + + .. py:attribute:: OP_ERR_CONNECT + + + + + .. py:attribute:: OP_ERR_VERSION + + + + + .. py:attribute:: OP_ERR_FIREWALL + + + + + .. py:attribute:: OP_ERR_MEMORY + + + + + .. py:attribute:: OP_ERR_INPUT + + + + + .. py:attribute:: OP_ERR_SOCKET_CLOSED + + + + + .. py:attribute:: OP_ERR_SISE_OVERFLOW + + + + + .. py:attribute:: OP_ERR_RQ_STRUCT_FAIL + + + + + .. py:attribute:: OP_ERR_RQ_STRING_FAIL + + + + + .. py:attribute:: OP_ERR_NO_DATA + + + + + .. py:attribute:: OP_ERR_OVER_MAX_DATA + + + + + .. py:attribute:: OP_ERR_DATA_RCV_FAIL + + + + + .. py:attribute:: OP_ERR_OVER_MAX_FID + + + + + .. py:attribute:: OP_ERR_REAL_CANCEL + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_INPUT + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_ACCTNO + + + + + .. py:attribute:: OP_ERR_OTHER_ACC_USE + + + + + .. py:attribute:: OP_ERR_MIS_2BILL_EXC + + + + + .. py:attribute:: OP_ERR_MIS_5BILL_EXC + + + + + .. py:attribute:: OP_ERR_MIS_1PER_EXC + + + + + .. py:attribute:: OP_ERR_MIS_3PER_EXC + + + + + .. py:attribute:: OP_ERR_SEND_FAIL + + + + + .. py:attribute:: OP_ERR_ORD_OVERFLOW + + + + + .. py:attribute:: OP_ERR_ORD_OVERFLOW2 + + + + + .. py:attribute:: OP_ERR_MIS_300CNT_EXC + + + + + .. py:attribute:: OP_ERR_MIS_500CNT_EXC + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_ACCTINFO + + + + + .. py:attribute:: OP_ERR_ORD_SYMCODE_EMPTY + + + + + .. py:attribute:: MSG_ERR_NONE + :annotation: = 정상처리 + + + + .. py:attribute:: MSG_ERR_FAIL + :annotation: = 실패 + + + + .. py:attribute:: MSG_ERR_COND_NOTFOUND + :annotation: = 조건번호 없음 + + + + .. py:attribute:: MSG_ERR_COND_MISMATCH + :annotation: = 조건번호와 조건식 틀림 + + + + .. py:attribute:: MSG_ERR_COND_OVERFLOW + :annotation: = 조건검색 조회요청 초과 + + + + .. py:attribute:: MSG_ERR_TR_FAIL + :annotation: = 전문 처리 실패 + + + + .. py:attribute:: MSG_ERR_LOGIN + :annotation: = 사용자정보 교환 실패 + + + + .. py:attribute:: MSG_ERR_CONNECT + :annotation: = 서버접속 실패 + + + + .. py:attribute:: MSG_ERR_VERSION + :annotation: = 버전처리 실패 + + + + .. py:attribute:: MSG_ERR_FIREWALL + :annotation: = 개인방화벽 실패 + + + + .. py:attribute:: MSG_ERR_MEMORY + :annotation: = 메모리보호 실패 + + + + .. py:attribute:: MSG_ERR_INPUT + :annotation: = 함수입력값 오류 + + + + .. py:attribute:: MSG_ERR_SOCKET_CLOSED + :annotation: = 통신 연결종료 + + + + .. py:attribute:: MSG_ERR_SISE_OVERFLOW + :annotation: = 시세조회 과부하 + + + + .. py:attribute:: MSG_ERR_RQ_STRUCT_FAIL + :annotation: = 전문작성 초기화 실패 + + + + .. py:attribute:: MSG_ERR_RQ_STRING_FAIL + :annotation: = 전문작성 입력값 오류 + + + + .. py:attribute:: MSG_ERR_NO_DATA + :annotation: = 데이터 없음 + + + + .. py:attribute:: MSG_ERR_OVER_MAX_DATA + :annotation: = 조회 가능한 종목수 초과 + + + + .. py:attribute:: MSG_ERR_DATA_RCV_FAIL + :annotation: = 데이터수신 실패 + + + + .. py:attribute:: MSG_ERR_OVER_MAX_FID + :annotation: = 조회 가능한 FID수 초과 + + + + .. py:attribute:: MSG_ERR_REAL_CANCEL + :annotation: = 실시간 해제 오류 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_INPUT + :annotation: = 입력값 오류 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_ACCTNO + :annotation: = 계좌 비밀번호 없음 + + + + .. py:attribute:: MSG_ERR_OTHER_ACC_USE + :annotation: = 타인계좌사용 오류 + + + + .. py:attribute:: MSG_ERR_MIS_2BILL_EXC + :annotation: = 주문가격이 20억원을 초과 + + + + .. py:attribute:: MSG_ERR_MIS_5BILL_EXC + :annotation: = 주문가격이 50억원을 초과 + + + + .. py:attribute:: MSG_ERR_MIS_1PER_EXC + :annotation: = 주문수량이 총발행주수의 1%초과오류 + + + + .. py:attribute:: MSG_ERR_MIS_3PER_EXC + :annotation: = 주문수량이 총발행주수의 3%초과오류 + + + + .. py:attribute:: MSG_ERR_SEND_FAIL + :annotation: = 주문전송 실패 + + + + .. py:attribute:: MSG_ERR_ORD_OVERFLOW + :annotation: = 주문전송 과부하 + + + + .. py:attribute:: MSG_ERR_ORD_OVERFLOW2 + :annotation: = 주문전송 과부하 + + + + .. py:attribute:: MSG_ERR_MIS_300CNT_EXC + :annotation: = 주문수량 300계약 초과 + + + + .. py:attribute:: MSG_ERR_MIS_500CNT_EXC + :annotation: = 주문수량 500계약 초과 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_ACCTINFO + :annotation: = 계좌정보없음 + + + + .. py:attribute:: MSG_ERR_ORD_SYMCODE_EMPTY + :annotation: = 종목코드없음 + + + + .. py:attribute:: ERROR_MESSAGE_BY_CODE + + + + + .. py:method:: get_error_message_by_code(cls, code: int, default: Optional[str] = None) + :classmethod: + + + .. py:method:: check_code_or_raise(cls, code: int) + :classmethod: + + + .. py:method:: wrap_to_check_code_or_raise(cls, func: CallableReturnsInt) -> CallableReturnsInt + :classmethod: + + + .. py:method:: try_or_raise(cls, arg: IntCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) -> IntCompatible + :classmethod: + + + .. py:method:: code(self) + :property: + + + +.. py:exception:: KiwoomOpenApiPlusBooleanReturnCodeError(code: Union[int, bool], message: Optional[str] = None) + + Bases: :py:obj:`KiwoomOpenApiPlusError` + + Common base class for all non-exit exceptions. + + .. py:attribute:: OP_ERR_SUCCESS + :annotation: = 1 + + + + .. py:attribute:: OP_ERR_FAILURE + :annotation: = 0 + + + + .. py:method:: check_code_or_raise(cls, code: IntOrBool, message: Optional[str] = None) -> IntOrBool + :classmethod: + + + .. py:method:: wrap_to_check_code_or_raise(cls, func: CallableReturnsIntOrBool, message: Optional[str] = None) -> CallableReturnsIntOrBool + :classmethod: + + + .. py:method:: try_or_raise(cls, arg: BoolCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) -> BoolCompatible + :classmethod: + + + .. py:method:: code(self) + :property: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.rst new file mode 100644 index 00000000..4fe81447 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.rst @@ -0,0 +1,192 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions` +================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions.KiwoomOpenApiPlusEventFunctions + + + + +.. py:class:: KiwoomOpenApiPlusEventFunctions + + .. py:method:: OnReceiveTrData(self, sScrNo: str, sRQName: str, sTrCode: str, sRecordName: str, sPrevNext: str, nDataLength: int, sErrorCode: str, sMessage: str, sSplmMsg: str) -> None + + 서버통신 후 데이터를 받은 시점을 알려준다. + + 요청했던 조회데이터를 수신했을때 발생됩니다. + 수신된 데이터는 이 이벤트내부에서 GetCommData() 함수를 이용해서 얻어올 수 있습니다. + + 파라미터 매핑: + - sRQName = CommRqData() 의 sRQName과 매핑되는 이름이다. + - sTrCode = CommRqData() 의 sTrCode과 매핑되는 이름이다. + + :param sScrNo: 화면번호 + :type sScrNo: str + :param sRQName: 사용자 구분명 + :type sRQName: str + :param sTrCode: TR 코드 + :type sTrCode: str + :param sRecordName: 레코드 명 + :type sRecordName: str + :param sPrevNext: 연속조회 유무 (0:추가조회 데이터 없음, 2:추가조회 데이터 있음) + :type sPrevNext: str + :param nDataLength: 사용안함 + :type nDataLength: str + :param sErrorCode: 사용안함 + :type sErrorCode: str + :param sMessage: 사용안함 + :type sMessage: str + :param sSplmMsg: 사용안함 + :type sSplmMsg: str + + :returns: None + + + .. py:method:: OnReceiveRealData(self, sRealKey: str, sRealType: str, sRealData: str) -> None + + 실시간데이터를 받은 시점을 알려준다. + + 실시간시세 데이터가 수신될때마다 종목단위로 발생됩니다. + SetRealReg() 함수로 등록한 실시간 데이터도 이 이벤트로 전달됩니다. + GetCommRealData() 함수를 이용해서 수신된 데이터를 얻을수 있습니다. + + :param sRealKey: 종목코드 + :type sRealKey: str + :param sRealType: 실시간 타입 + :type sRealType: str + :param sRealData: 실시간 데이터전문 (사용불가) + :type sRealData: str + + :returns: None + + + .. py:method:: OnReceiveMsg(self, sScrNo: str, sRQName: str, sTrCode: str, sMsg: str) -> None + + 서버통신 후 메시지를 받은 시점을 알려준다. + + 주문전송 또는 데이터 조회요청 후 서버 메시지가 수신됩니다. + ※ 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다. + + 파라미터 매핑: + - sScrNo = CommRqData() 의 sScrNo와 매핑된다. + - sRQName = CommRqData() 의 sRQName 와 매핑된다. + - sTrCode = CommRqData() 의 sTrCode 와 매핑된다. + + 메시지 예시: + - "조회가 완료되었습니다." + - "증거금 부족으로 주문이 거부되었습니다." + - "정정할 원주문 내역이 없습니다." + - "비밀번호 입력을 확인해주시기 바랍니다." + + :param sScrNo: str, sRQName: str, sTrCode: str, sMsg: str + + :returns: None + + + .. py:method:: OnReceiveChejanData(self, sGubun: str, nItemCnt: int, sFIdList: str) -> None + + 체결데이터를 받은 시점을 알려준다. + + 주문전송 후 주문접수, 체결통보, 잔고통보를 수신할 때 마다 발생됩니다. + GetChejanData() 함수를 이용해서 FID 항목별 값을 얻을수 있습니다. + + :param sGubun: 체결구분 (0:주문체결통보, 1:국내주식 잔고통보, 4:파생상품 잔고통보) + :type sGubun: str + :param nItemCnt: 아이템 개수 + :type nItemCnt: int + :param sFIdList: 데이터 리스트 (';' 구분자) + :type sFIdList: str + + :returns: None + + + .. py:method:: OnEventConnect(self, nErrCode: int) -> None + + 서버 접속 관련 이벤트. + + 로그인 처리 이벤트입니다. 성공이면 인자값 nErrCode가 0이며 에러는 다음과 같은 값이 전달됩니다. + + 에러코드 구분: + - OP_ERR_LOGIN(-100): 사용자 정보교환 실패 + - OP_ERR_CONNECT(-101): 서버접속 실패 + - OP_ERR_VERSION(-102): 버전처리 실패 + + :param nErrCode: 에러코드 (0:로그인 성공, 음수:실패) + :type nErrCode: int + + :returns: None + + + .. py:method:: OnReceiveInvestRealData(self, sRealKey: str) -> None + + 더 이상 지원하지 않는 함수. + + + .. py:method:: OnReceiveRealCondition(self, sTrCode: str, strType: str, strConditionName: str, strConditionIndex: str) -> None + + 조건검색 실시간 편입,이탈 종목을 받을 시점을 알려준다. + + 실시간 조건검색 요청으로 신규종목이 편입되거나 기존 종목이 이탈될때 마다 발생됩니다. + ※ 편입되었다가 순간적으로 다시 이탈되는 종목에대한 신호는 조건검색 서버마다 차이가 발생할 수 있습니다. + + strConditionName 에 해당하는 종목이 실시간으로 들어옴. + strType 으로 편입된 종목인지 이탈된 종목인지 구분한다. + + :param sTrCode: 종목코드 + :type sTrCode: str + :param strType: 편입/이탈 구분 (I:편입, D:이탈) + :type strType: str + :param strConditionName: 조건식 이름 + :type strConditionName: str + :param strConditionIndex: 조건식 인덱스 + :type strConditionIndex: str + + :returns: None + + + .. py:method:: OnReceiveTrCondition(self, sScrNo: str, strCodeList: str, strConditionName: str, nIndex: int, nNext: int) -> None + + 조건검색 조회응답으로 종목리스트를 받는 시점. + + 조건검색 요청에대한 서버 응답 수신시 발생하는 이벤트입니다. + 종목코드 리스트는 각 종목코드가 ';' 로 구분되서 전달됩니다. + + :param sScrNo: 화면번호 + :type sScrNo: str + :param strCodeList: 종목리스트 (';' 구분자) + :type strCodeList: str + :param strConditionName: 조건식 이름 + :type strConditionName: str + :param nIndex: 조건식 인덱스 + :type nIndex: int + :param nNext: 연속조회 여부 (2:연속조회, 0:연속조회 없음) + :type nNext: int + + :returns: None + + + .. py:method:: OnReceiveConditionVer(self, lRet: int, sMsg: str) -> None + + 로컬에 사용자 조건식 저장 성공 여부를 확인하는 시점. + + 저장된 사용자 조건식 불러오기 요청에 대한 응답 수신시 발생되는 이벤트입니다. + + :param lRet: 사용자 조건식 저장 성공여부 (1:성공, 나머지:실패) + :type lRet: int + :param sMsg: 호출결과 메시지 + :type sMsg: str + + :returns: None + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.rst new file mode 100644 index 00000000..b12bf0d8 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.rst @@ -0,0 +1,66 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler` +=============================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusEventHandler(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions.KiwoomOpenApiPlusEventHandlerFunctions` + + .. py:method:: control(self) + :property: + + + .. py:method:: observer(self) + :property: + + + .. py:method:: names(cls) + :classmethod: + + + .. py:method:: slots(self) + + + .. py:method:: connect(self) + + + .. py:method:: disconnect(self) + + + .. py:method:: on_enter(self) + + + .. py:method:: on_exit(self, exc_type=None, exc_value=None, traceback=None) + + + .. py:method:: add_callback(self, callback, *args, **kwargs) + + + .. py:method:: enter(self) + + + .. py:method:: exit(self, exc_type=None, exc_value=None, traceback=None) + + + .. py:method:: stop(self) + + + .. py:method:: close(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.rst new file mode 100644 index 00000000..a4ca5120 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.rst @@ -0,0 +1,54 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions` +======================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions.KiwoomOpenApiPlusEventHandlerFunctions + + + + +.. py:class:: KiwoomOpenApiPlusEventHandlerFunctions + + .. py:method:: OnEventConnect(self, errcode) + :abstractmethod: + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + :abstractmethod: + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + :abstractmethod: + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + :abstractmethod: + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + :abstractmethod: + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + :abstractmethod: + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + :abstractmethod: + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + :abstractmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst new file mode 100644 index 00000000..d5df769f --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst @@ -0,0 +1,58 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature` +======================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature.KiwoomOpenApiPlusEventHandlerSignature + + + + +.. py:class:: KiwoomOpenApiPlusEventHandlerSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: EVENT_HANDLER_SIGNATURES_BY_NAME + :annotation: :Dict[str, KiwoomOpenApiPlusEventHandlerSignature] + + + + .. py:method:: from_name(cls, name: str) -> KiwoomOpenApiPlusEventHandlerSignature + :classmethod: + + + .. py:method:: names(cls) -> List[str] + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.rst new file mode 100644 index 00000000..52d06377 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.rst @@ -0,0 +1,61 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler` +====================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusLoggingEventHandler(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + [OnReceiveMsg()이벤트] + + OnReceiveMsg( + BSTR sScrNo, // 화면번호 + BSTR sRQName, // 사용자 구분명 + BSTR sTrCode, // TR이름 + BSTR sMsg // 서버에서 전달하는 메시지 + ) + + 서버통신 후 수신한 메시지를 알려줍니다. + 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 + 이 코드번호로 분류하시면 안됩니다. + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.rst new file mode 100644 index 00000000..49de484b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.rst @@ -0,0 +1,53 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget` +============================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget.KiwoomOpenApiPlusQAxWidget + + + + +.. py:class:: KiwoomOpenApiPlusQAxWidget(c: Optional[str] = None, parent: Optional[koapy.compat.pyside2.QtWidgets.QWidget] = None, f: koapy.compat.pyside2.QtCore.Qt.WindowFlags = Qt.WindowFlags()) KiwoomOpenApiPlusQAxWidget(parent: Optional[koapy.compat.pyside2.QtWidgets.QWidget] = None, f: koapy.compat.pyside2.QtCore.Qt.WindowFlags = Qt.WindowFlags()) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging`, :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetMixin` + + KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 + KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다. + + .. py:attribute:: CLSID + :annotation: = {A1574A0D-6BFA-4BD7-9020-DED88711818D} + + + + .. py:attribute:: PROGID + :annotation: = KHOPENAPI.KHOpenApiCtrl.1 + + + + .. py:attribute:: METHOD_NAMES + + + + + .. py:attribute:: EVENT_NAMES + + + + + .. py:method:: changeEvent(self, event) + + + .. py:method:: closeEvent(self, event) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.rst new file mode 100644 index 00000000..c16713b9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.rst @@ -0,0 +1,421 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin` +================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetUniversalMixin + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetServerSideMixin + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetMixin + + + + +.. py:class:: KiwoomOpenApiPlusQAxWidgetUniversalMixin + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions` + + 일차적으로 KiwoomOpenApiPlusQAxWidget 객체에 대해 사용될 수 있는 Mixin 이지만, + 넓게는 다른 KiwoomOpenApiPlusDispatchFunctions 인터페이스를 지원하는 모든 객체에서 사용될 수 있는, + 단순하면서도 유니버셜한 메소드들이 구현되어 있는 Mixin 입니다. + + .. py:method:: IsConnected(self) + + 키움증권 서버에 접속되었는지 여부를 반환합니다. + + + .. py:method:: ShowAccountWindow(self) + + 계좌 비밀번호 및 자동 로그인 처리 관련 설정창을 표시합니다. + + + .. py:method:: GetServerGubun(self) + + 접속된 서버의 종류를 확인해 구분값을 반환합니다. + + + .. py:method:: IsSimulationServer(self) + + 모의투자 서버 접속 여부를 확인해 반환합니다. + + + .. py:method:: IsRealServer(self) + + 실 서버 접속 여부를 확인해 반환합니다. + + + .. py:method:: GetMasterStockInfo(self, code) + + 주식의 종목분류, 시장구분등의 정보를 제공합니다. + + + .. py:method:: GetMasterStockInfoAsDict(self, code) + + 주식의 종목분류, 시장구분등의 정보를 딕셔너리 형태로 가공하여 제공합니다. + + + .. py:method:: SetConditionSearchFlag(self, flag) + + 조건 검색시 동작과 관련된 플래그를 설정합니다. + + + .. py:method:: AddPriceToConditionSearchResult(self) + + 조건 검색시 현재가를 함께 수신하도록 설정합니다. + + + .. py:method:: DelPriceFromConditionSearchResult(self) + + 조건 검색시 현재가를 함께 수신하지 않도록 설정합니다. + + + .. py:method:: GetUpjongCode(self, code) + + 업종코드 목록을 반환합니다. + + 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + + + .. py:method:: GetUpjongCodeAsList(self, code) + + 업종코드 목록을 리스트 형태로 가공하여 반환합니다. + + 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. + 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 + + + .. py:method:: GetUpjongNameByCode(self, code) + + 주어진 업종코드의 이름을 반환합니다. + + + .. py:method:: IsOrderWarningETF(self, code) + + ETF 의 투자유의 종목 여부를 반환합니다. + + 투자유의 종목인 경우 "1" 값이 리턴, + 그렇지 않은 경우 "0" 값 리턴. + ETF가 아닌 종목을 입력시 "0" 값 리턴. + + + .. py:method:: IsOrderWarningETFAsBoolean(self, code) + + ETF 의 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. + + + .. py:method:: IsOrderWarningStock(self, code) + + 주식 전종목 대상 투자유의 종목 여부를 반환합니다. + + 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 + + + .. py:method:: IsOrderWarningStockAsBoolean(self, code) + + 주식 전종목 대상 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. + + + .. py:method:: GetMasterListedStockCntEx(self, code) + + 종목의 상장 주식수를 반환합니다. + + 기존의 GetMasterListedStockCnt() 함수 사용시 발생할 수 있는 오버플로우 문제를 해결합니다. + + + .. py:method:: GetMasterListedStockCntExAsInt(self, code) + + 종목의 상장 주식수를 정수 형태로 변환하여 반환합니다. + + + .. py:method:: GetCodeListByMarketAsList(self, market: Optional[Union[str, int]] = None) + + 시장의 종목 코드 목록를 리스트 형태로 가공하여 반환합니다. + + + .. py:method:: GetNameListByMarketAsList(self, market: Optional[Union[str, int]] = None) + + 시장의 종목 이름 목록를 리스트 형태로 가공하여 반환합니다. + + + .. py:method:: GetUserId(self) + + 사용자 ID 를 반환합니다. + + + .. py:method:: GetUserName(self) + + 사용자 이름을 반환합니다. + + + .. py:method:: GetAccountCount(self) + + 계좌 개수를 반환합니다. + + + .. py:method:: GetAccountList(self) + + 계좌 목록을 리스트 형태로 가공하여 반환합니다. + + + .. py:method:: GetKeyboardSecurityStatus(self) + + 키보드 보안 설정 상태를 반환합니다. + + + .. py:method:: IsKeyboardSecurityEnabled(self) + + 키보드 보안 설정 상태를 불리언 형태로 변환하여 반환합니다. + + + .. py:method:: GetFirewallStatus(self) + + 방화벽 설정 상태를 반환합니다. + + + .. py:method:: IsFirewallEnabled(self) + + 방화벽 설정 상태를 불리언 형태로 변환하여 반환합니다. + + + .. py:method:: GetFirstAvailableAccount(self) + + 확인 가능한 첫번째 계좌번호를 반환합니다. + + + .. py:method:: GetMasterStockStateAsList(self, code: str) + + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 + 리스트 형태로 가공하여 전달합니다. + + + .. py:method:: GetKospiCodeList(self) + + 장내 종목 코드 목록을 반환합니다. + + + .. py:method:: GetKosdaqCodeList(self) + + 코스닥 시장내 종목 코드 목록을 반환합니다. + + + .. py:method:: GetGeneralCodeList(self, include_preferred_stock: bool = False, include_etn: bool = False, include_etf: bool = False, include_mutual_fund: bool = False, include_reits: bool = False, include_kosdaq: bool = False) + + 장내 종목 코드 목록중 특정 그룹을 포함시키고 혹은 제거하고 반환합니다. + + + .. py:method:: GetStockStates(self, code: str) + + 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. + + + .. py:method:: GetSurveillanceFlag(self, code: str) + + 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) + + + .. py:method:: IsSuspended(self, code: str) + + 거래정지 여부를 반환합니다. + + + .. py:method:: IsUnderSurveillance(self, code: str) + + 감리종목 여부를 반환합니다. + + + .. py:method:: IsUnderAdministration(self, code: str) + + 관리종목 여부를 반환합니다. + + + .. py:method:: IsFlaggedForCaution(self, code: str) + + 감리구분이 정상이 아니거나 상태값중 투자유의종목으로 지정된 경우 참을 반환합니다. + + + .. py:method:: IsNotNormal(self, code: str) + + 감리구분이 정상이 아니거나 상태값중 거래정지, 감리종목, 관리종목, 투자유의종목 등으로 지정된 경우 참을 반환합니다. + + + .. py:method:: IsNormal(self, code: str) + + 감리구분이 정상이고 별다른 이상 상태값이 없는 경우 참을 반환합니다. + + + .. py:method:: GetConditionFilePath(self) + + 조건식 데이터를 로드한 후 생성되는 조건검색 관련 데이터 파일의 경로를 반환합니다. + + + .. py:method:: GetConditionNameListAsList(self) + + 조건식 데이터를 로드한 후 확인 가능한 조건식 목록을 리스트 형태로 가공하여 반환합니다. + + + .. py:method:: GetAutoLoginDatPath(self) + + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일의 경로를 반환합니다. + + + .. py:method:: IsAutoLoginEnabled(self) + + 자동 로그인 설정 여부를 반환합니다. + + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는지의 여부를 확인합니다. + + + .. py:method:: DisableAutoLogin(self) + + 자동 로그인 설정을 해제합니다. + + 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는 경우 해당 파일을 삭제합니다. + + + .. py:method:: RunScriptInSubprocess_WithData(cls, main: Callable[Ellipsis, Any], data: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False, stdin: Optional[int] = subprocess.PIPE, stdout: Optional[int] = None) + :classmethod: + + + .. py:method:: LoginUsingPywinauto_Impl(cls, credentials: Optional[Mapping[str, Any]] = None) + :classmethod: + + + .. py:method:: LoginUsingPywinauto_RunScriptInSubprocess(cls, credentials: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False) + :classmethod: + + + .. py:method:: LoginUsingPywinauto(self, credentials: Optional[Mapping[str, Any]] = None, wait: bool = True, timeout: bool = None, check: bool = True) + + 자식 프로세스 내에서 pywinauto 를 사용해 로그인 처리를 자동으로 진행합니다. + + + .. py:method:: CommConnectAndThen(self, credentials: Mapping[str, Any], callback: Callable[[int], Any]) -> int + CommConnectAndThen(self, credentials: Mapping[str, Any]) -> int + CommConnectAndThen(self, callback: Callable[[int], Any]) -> int + CommConnectAndThen(self) -> int + + 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 특정 콜백 함수를 실행합니다. + + + .. py:method:: Connect(self, credentials: Optional[Mapping[str, Any]] = None) -> int + + 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 확인 가능한 에러코드 값을 반환합니다. + + + .. py:method:: EnsureConnectedAndThen(self, credentials: Mapping[str, Any], callback: Callable[[int], Any]) -> bool + EnsureConnectedAndThen(self, credentials: Mapping[str, Any]) -> bool + EnsureConnectedAndThen(self, callback: Callable[[int], Any]) -> bool + EnsureConnectedAndThen(self) -> bool + + 로그인 여부를 확인하고 로그인 상태를 보장한 뒤에 주어진 콜백 함수를 실행합니다. + + 로그인 여부 확인시 로그인 되어있지 않다면 로그인을 진행한 뒤 주어진 콜백 함수를 실행합니다. + 이미 로그인이 되어있다면 즉시 주어진 콜백 함수를 실행합니다. + + + .. py:method:: EnsureConnected(self, credentials: Optional[Mapping[str, Any]] = None) -> bool + + 로그인 상태를 보장하도록 합니다. + + 이미 로그인이 되어있는 경우 별다른 처리를 하지 않습니다. + 로그인이 되어있지 않다면 로그인을 수행합니다. + + + .. py:method:: EnableAutoLoginUsingPywinauto_Impl(cls, account_passwords: Optional[Mapping[str, Any]] = None) + :classmethod: + + + .. py:method:: EnableAutoLoginUsingPywinauto_RunScriptInSubprocess(cls, account_passwords: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False) + :classmethod: + + + .. py:method:: EnableAutoLoginUsingPywinauto(self, credentials: Optional[Mapping[str, Any]] = None, wait: bool = True, timeout: bool = None, check: bool = True) + + 자식 프로세스 내에서 pywinauto 를 사용해 자동 로그인 설정을 자동으로 진행합니다. + + + .. py:method:: EnableAutoLogin(self, credentials: Optional[Mapping[str, Any]] = None) + + 자동 로그인을 설정합니다. + + + .. py:method:: EnsureAutoLoginEnabled(self, credentials: Optional[Mapping[str, Any]] = None) -> bool + + 자동 로그인이 설정되어 있음을 보장하도록 합니다. + + 이미 자동 로그인이 설정 되어있는 경우 별다른 처리를 하지 않습니다. + 자동 로그인이 설정되어 있지 않다면 자동 로그인을 설정을 처리합니다. + + + .. py:method:: HandleVersionUpgradeUsingPywinauto_Impl(cls, pid) + :classmethod: + + + .. py:method:: HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess(cls, pid: int, wait: bool = False, timeout: bool = None, check: bool = False) + :classmethod: + + + .. py:method:: HandleVersionUpgradeUsingPywinauto(self, pid: int, wait: bool = True, timeout: bool = None, check: bool = True) + + 자식 프로세스 내에서 pywinauto 를 사용해 버전 업그레이드 처리를 자동으로 진행합니다. + + + +.. py:class:: KiwoomOpenApiPlusQAxWidgetServerSideMixin + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions`, :py:obj:`koapy.utils.logging.Logging.Logging` + + KiwoomOpenApiPlusQAxWidget 객체에 대해 Server-Side 에서만 사용되는 Mixin 입니다. + + 주로 서버 환경에서만 확인하거나 처리가 가능한 아래 기능들을 커버합니다: + + - 조건검색식 로드 + - 조회 횟수 제한 회피 기능 + + .. py:method:: LoadCondition(self) -> int + + 조건검색 관련 조건식을 불러옵니다. + + + .. py:method:: IsConditionLoaded(self) -> bool + + 조건식이 로드 되었는지 여부를 반환합니다. + + + .. py:method:: EnsureConditionLoaded(self, force: bool = False) -> int + + 조건식이 로드됨을 보장하도록 합니다. + + 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. + 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. + + + .. py:method:: CommRqDataWithInputs(self, rqname: str, trcode: str, prevnext: Union[str, int], scrnno: str, inputs: Optional[Dict[str, str]] = None) -> int + + CommRqData() 호출 이전에 주어진 입력값을로 SetInputValue() 호출을 통한 입력값 설정을 진행합니다. + 이후 CommRqData() 를 호출합니다. + + + .. py:method:: AtomicCommRqData(self, rqname: str, trcode: str, prevnext: Union[str, int], scrnno: str, inputs: Optional[Dict[str, str]] = None) -> int + + SetInputValue() 호출을 통한 입력값 설정 및 CommRqData() 호출을 하나의 단위로 처리할 수 있도록 Lock 을 걸고 처리합니다. + + + +.. py:class:: KiwoomOpenApiPlusQAxWidgetMixin + + Bases: :py:obj:`KiwoomOpenApiPlusQAxWidgetUniversalMixin`, :py:obj:`KiwoomOpenApiPlusQAxWidgetServerSideMixin` + + KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 + KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다. + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.rst new file mode 100644 index 00000000..52eb0aec --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.rst @@ -0,0 +1,62 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter` +============================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusCommRqDataRateLimiter + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusSendOrderRateLimiter + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusSendConditionRateLimiter + + + + +.. py:class:: KiwoomOpenApiPlusCommRqDataRateLimiter + + Bases: :py:obj:`koapy.utils.rate_limiting.RateLimiter.CompositeTimeWindowRateLimiter` + + [조회횟수 제한 관련 가이드] + - 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기 + - 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기 + - 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기 + + +.. py:class:: KiwoomOpenApiPlusSendOrderRateLimiter + + Bases: :py:obj:`koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter` + + +.. py:class:: KiwoomOpenApiPlusSendConditionRateLimiter(comm_rate_limiter) + + Bases: :py:obj:`koapy.utils.rate_limiting.RateLimiter.RateLimiter` + + [조건검색 제한] + - 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다. + + [조건검색 제한] + 조건검색 요청은 1초당 5회 조회횟수 제한에 포함됩니다. + 동일 조건식에 대한 조건검색 요청은 1분에 1회로 제한됩니다. + 조건검색 결과가 100종목을 넘게 되면 해당조건은 실시간 조건검색 신호를 수신할 수 없습니다. + 실시간 조건검색은 최대 10개까지 사용 가능합니다. + + .. py:method:: get_limiter_per_condition(self, condition_name, condition_index) + + + .. py:method:: check_sleep_seconds(self, fn, *args, **kwargs) + + + .. py:method:: add_call_history(self, fn, *args, **kwargs) + + + .. py:method:: sleep_if_necessary(self, fn, *args, **kwargs) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.rst new file mode 100644 index 00000000..82784ca5 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.rst @@ -0,0 +1,174 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType` +=========================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.KiwoomOpenApiPlusRealType + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.main + + + +.. py:class:: KiwoomOpenApiPlusRealType(gidc: Optional[str] = None, desc: Optional[str] = None, nfid: Optional[int] = None, fids: Optional[List[int]] = None) + + Bases: :py:obj:`koapy.utils.serialization.JsonSerializable`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:class:: Fid(fid: Optional[int] = None, name: Optional[str] = None) + + Bases: :py:obj:`koapy.utils.serialization.JsonSerializable` + + .. py:attribute:: FID_DUMP_FILEDIR + + + + + .. py:attribute:: FID_DUMP_FILENAME + :annotation: = fid.csv + + + + .. py:attribute:: FID_DUMP_FILEPATH + + + + + .. py:attribute:: FID_DUMP_PROCESSOR + + + + + .. py:attribute:: FID_BY_FID + :annotation: :Dict[int, KiwoomOpenApiPlusRealType] + + + + .. py:attribute:: FID_BY_NAME + :annotation: :Dict[str, KiwoomOpenApiPlusRealType] + + + + .. py:method:: fids_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike]] = None, encoding: Optional[str] = None) -> Dict[int, str] + :classmethod: + + + .. py:method:: load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike]] = None) + :classmethod: + + + .. py:method:: from_fid(cls, fid: Union[str, int]) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: get_name_by_fid(cls, fid: Union[str, int], default: Optional[str] = None) -> Optional[str] + :classmethod: + + + + .. py:attribute:: REALTYPE_BY_DESC_DUMP_FILEDIR + + + + + .. py:attribute:: REALTYPE_BY_DESC_DUMP_FILENAME + :annotation: = realtype_by_desc.json + + + + .. py:attribute:: REALTYPE_BY_DESC_DUMP_FILEPATH + + + + + .. py:attribute:: REALTYPE_BY_DESC + :annotation: :Dict[str, KiwoomOpenApiPlusRealType] + + + + .. py:method:: get_realtype_name_list(cls) + :classmethod: + + + .. py:method:: get_realtype_info_list(cls) + :classmethod: + + + .. py:method:: get_realtype_info_by_desc(cls, desc: str) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: get_realtype_info_by_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: get_realtype_info_by_realtype_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: get_fids_by_realtype_name(cls, name: str) -> Optional[List[int]] + :classmethod: + + + .. py:method:: get_fids_by_realtype_name_as_string(cls, name: str) -> Optional[str] + :classmethod: + + + .. py:method:: get_field_names_by_realtype_name(cls, name: str) -> Optional[List[str]] + :classmethod: + + + .. py:method:: realtypes_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None, encoding: Optional[str] = None, module_path: Optional[str] = None) -> List[KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: realtype_by_desc_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None) -> Dict[str, KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: dump_realtype_by_desc(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None, encoding: Optional[str] = None) + :classmethod: + + + .. py:method:: realtype_by_desc_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, encoding: Optional[str] = None) -> Dict[str, KiwoomOpenApiPlusRealType] + :classmethod: + + + .. py:method:: load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None) + :classmethod: + + + .. py:method:: load_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None) + :classmethod: + + + .. py:method:: load(cls) + :classmethod: + + + +.. py:function:: main() + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.rst new file mode 100644 index 00000000..e18edeab --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.rst @@ -0,0 +1,55 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager` +================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager.KiwoomOpenApiPlusScreenManager + + + + +.. py:class:: KiwoomOpenApiPlusScreenManager(control: Optional[koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions] = None) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:attribute:: MAXIMUM_NUMBER_OF_SCREENS + :annotation: = 200 + + + + .. py:method:: number_to_screen_no(number: int) -> str + :staticmethod: + + + .. py:method:: screen_no_to_number(screen_no: str) -> int + :staticmethod: + + + .. py:method:: is_inuse(self, screen_no: str) -> bool + + + .. py:method:: get_single_free_screen(self, exclude: Optional[Collection[str]] = None) -> str + + + .. py:method:: get_multiple_free_screens(self, count: int) -> List[str] + + + .. py:method:: get_free_screen(self, count: Optional[int] = None) -> Union[str, List[str]] + + + .. py:method:: borrow_screen(self, screen_no: Optional[str] = None, reuse: bool = True, pop: bool = True) -> str + + + .. py:method:: return_screen(self, screen_no: str) -> bool + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.rst new file mode 100644 index 00000000..20fe4810 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.rst @@ -0,0 +1,80 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector` +================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.KiwoomOpenApiPlusSignalConnector + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.P + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.R + + +.. py:data:: P + + + + +.. py:data:: R + + + + +.. py:class:: KiwoomOpenApiPlusSignalConnector(name: str) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging`, :py:obj:`Generic`\ [\ :py:obj:`P`\ , :py:obj:`R`\ ] + + Abstract base class for generic types. + + A generic type is typically declared by inheriting from + this class parameterized with one or more type variables. + For example, a generic mapping type might be defined as:: + + class Mapping(Generic[KT, VT]): + def __getitem__(self, key: KT) -> VT: + ... + # Etc. + + This class can then be used as follows:: + + def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: + try: + return mapping[key] + except KeyError: + return default + + .. py:method:: is_valid_slot(self, slot: Callable[Ellipsis, Any]) -> bool + + + .. py:method:: connect_to(self, control: koapy.compat.pyside2.QtAxContainer.QAxWidget) + + + .. py:method:: disconnect_from(self, control: koapy.compat.pyside2.QtAxContainer.QAxWidget) + + + .. py:method:: connect(self, slot: Callable[Ellipsis, Any]) + + + .. py:method:: disconnect(self, slot: Optional[Callable[Ellipsis, Any]] = None) + + + .. py:method:: call(self, *args: P, **kwargs: P) -> R + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst new file mode 100644 index 00000000..5897cbef --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst @@ -0,0 +1,75 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature` +============================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.NoneType + + +.. py:data:: NoneType + + + + +.. py:class:: KiwoomOpenApiPlusSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty) + + Bases: :py:obj:`inspect.Signature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: PYTHONTYPE_TO_QTTYPE + + + + + .. py:attribute:: COMTYPE_TO_PYTHONTYPE + + + + + .. py:method:: name(self) -> str + :property: + + + .. py:method:: to_pyside2_function_prototype(self) -> str + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.rst new file mode 100644 index 00000000..0d8dcf04 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.rst @@ -0,0 +1,137 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo` +========================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.KiwoomOpenApiPlusTrInfo + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.main + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.infer_fids_by_tr_outputs + + + +.. py:class:: KiwoomOpenApiPlusTrInfo(tr_code: Optional[str] = None, name: Optional[str] = None, tr_name: Optional[str] = None, tr_names_svr: Optional[str] = None, tr_type: Optional[str] = None, gfid: Optional[str] = None, inputs: Optional[Sequence[Field]] = None, single_outputs_name: Optional[str] = None, single_outputs: Optional[Sequence[Field]] = None, multi_outputs_name: Optional[str] = None, multi_outputs: Optional[Sequence[Field]] = None) + + Bases: :py:obj:`koapy.utils.serialization.JsonSerializable`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:class:: Field(name: Optional[str] = None, start: Optional[int] = None, offset: Optional[int] = None, fid: Optional[int] = None) + + Bases: :py:obj:`koapy.utils.serialization.JsonSerializable` + + + .. py:attribute:: TRINFO_BY_CODE_DUMP_FILEDIR + + + + + .. py:attribute:: TRINFO_BY_CODE_DUMP_FILENAME + :annotation: = trinfo_by_code.json + + + + .. py:attribute:: TRINFO_BY_CODE_DUMP_FILEPATH + + + + + .. py:attribute:: TRINFO_BY_CODE + :annotation: :Dict[str, KiwoomOpenApiPlusTrInfo] + + + + .. py:attribute:: SINGLE_TO_MULTI_TRCODES + :annotation: = ['opt10072', 'opt10073', 'opt10075', 'opt10076', 'opt10085', 'optkwfid', 'optkwinv', 'optkwpro'] + + + + .. py:method:: to_dict(self) -> Dict[str, Any] + + + .. py:method:: from_dict(cls, dic: Dict[str, Any]) -> KiwoomOpenApiPlusTrInfo + :classmethod: + + + .. py:method:: get_input_names(self) -> List[str] + + + .. py:method:: get_single_output_names(self) -> List[str] + + + .. py:method:: get_multi_output_names(self) -> List[str] + + + .. py:method:: get_trcode_list(cls) -> List[str] + :classmethod: + + + .. py:method:: get_trinfo_list(cls) -> List[KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: get_trinfo_by_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: from_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: from_encfile(cls, f: Union[str, os.PathLike, TextIO], tr_code: Optional[str] = None, encoding: Optional[str] = None) -> KiwoomOpenApiPlusTrInfo + :classmethod: + + + .. py:method:: infos_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None, encoding: Optional[str] = None, module_path: Optional[str] = None) -> List[KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: swap_output_types(cls, item: KiwoomOpenApiPlusTrInfo) -> KiwoomOpenApiPlusTrInfo + :classmethod: + + + .. py:method:: trinfo_by_code_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None, post_process: bool = True) -> Dict[str, KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: dump_trinfo_by_code(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, data_dir: Optional[str] = None, encoding: Optional[str] = None) + :classmethod: + + + .. py:method:: trinfo_by_code_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, encoding: Optional[str] = None) -> Dict[str, KiwoomOpenApiPlusTrInfo] + :classmethod: + + + .. py:method:: load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None) + :classmethod: + + + .. py:method:: load_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None) + :classmethod: + + + .. py:method:: load(cls) + :classmethod: + + + +.. py:function:: main() + + +.. py:function:: infer_fids_by_tr_outputs(output_filename=None) + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.rst new file mode 100644 index 00000000..0e3f02e0 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib` +========================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib + + +Module Contents +--------------- + +.. py:data:: TYPELIB + + + + +.. py:data:: DISPATCH_OLE_ITEM + + + + +.. py:data:: EVENT_OLE_ITEM + + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.rst new file mode 100644 index 00000000..596d2a5b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.rst @@ -0,0 +1,64 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec` +============================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec + + +Module Contents +--------------- + +.. py:data:: CONTROL_PROGID + :annotation: = KHOPENAPI.KHOpenApiCtrl.1 + + + +.. py:data:: CONTROL_CLSID + + + + +.. py:data:: DISPATCH_CLSID + + + + +.. py:data:: EVENT_CLSID + + + + +.. py:data:: MODULE_CLSID + + + + +.. py:data:: TYPELIB_SPECS + + + + +.. py:data:: TYPELIB_SPEC + + + + +.. py:data:: TYPELIB_DLL_PATH + + + + +.. py:data:: API_MODULE_PATH_FROM_DEFAULT_INSTALLATION + + + + +.. py:data:: API_MODULE_PATH_FROM_TYPELIB_DLL + + + + +.. py:data:: API_MODULE_PATH + + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.rst new file mode 100644 index 00000000..43d186d5 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.rst @@ -0,0 +1,75 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater` +================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater.KiwoomOpenApiPlusVersionUpdater + + + + +.. py:class:: KiwoomOpenApiPlusVersionUpdater(credentials) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: get_api_module_path(self) + + + .. py:method:: get_autologin_dat(self) + + + .. py:method:: is_autologin_enabled(self) + + + .. py:method:: disable_autologin(self) + + + .. py:method:: open_login_window_impl(cls) + :classmethod: + + + .. py:method:: open_login_window(self) + + + .. py:method:: show_account_window_impl(cls) + :classmethod: + + + .. py:method:: show_account_window(self) + + + .. py:method:: check_apply_simulation_window(cls) + :classmethod: + + + .. py:method:: login_using_pywinauto(cls, credentials) + :classmethod: + + + .. py:method:: enable_autologin_using_pywinauto(cls, credentials) + :classmethod: + + + .. py:method:: enable_autologin(self) + + + .. py:method:: handle_version_upgrade_using_pywinauto(cls, pid) + :classmethod: + + + .. py:method:: try_version_update_using_pywinauto(self) + + + .. py:method:: update_version_if_necessary(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.rst new file mode 100644 index 00000000..d015c9f5 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.rst @@ -0,0 +1,46 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core` +================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + tools/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiPlusCondition/index.rst + KiwoomOpenApiPlusDispatchFunctions/index.rst + KiwoomOpenApiPlusDispatchSignature/index.rst + KiwoomOpenApiPlusDynamicCallable/index.rst + KiwoomOpenApiPlusEntrypoint/index.rst + KiwoomOpenApiPlusEntrypointMixin/index.rst + KiwoomOpenApiPlusError/index.rst + KiwoomOpenApiPlusEventFunctions/index.rst + KiwoomOpenApiPlusEventHandler/index.rst + KiwoomOpenApiPlusEventHandlerFunctions/index.rst + KiwoomOpenApiPlusEventHandlerSignature/index.rst + KiwoomOpenApiPlusLoggingEventHandler/index.rst + KiwoomOpenApiPlusQAxWidget/index.rst + KiwoomOpenApiPlusQAxWidgetMixin/index.rst + KiwoomOpenApiPlusRateLimiter/index.rst + KiwoomOpenApiPlusRealType/index.rst + KiwoomOpenApiPlusScreenManager/index.rst + KiwoomOpenApiPlusSignalConnector/index.rst + KiwoomOpenApiPlusSignature/index.rst + KiwoomOpenApiPlusTrInfo/index.rst + KiwoomOpenApiPlusTypeLib/index.rst + KiwoomOpenApiPlusTypeLibSpec/index.rst + KiwoomOpenApiPlusVersionUpdater/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.rst new file mode 100644 index 00000000..d5a6a776 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs` +============================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs.generate_python_stubs + + + +.. py:function:: generate_python_stubs(dispatch_class_name=None, dispatch_file_path=None, event_class_name=None, event_file_path=None, encoding=None, force_overwrite=False) + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.rst new file mode 100644 index 00000000..a6701055 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.core.tools` +======================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.core.tools + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + generate_python_stubs/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.rst new file mode 100644 index 00000000..f157714a --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.rst @@ -0,0 +1,34 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient` +================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient.KiwoomOpenApiPlusServiceClient + + + + +.. py:class:: KiwoomOpenApiPlusServiceClient(host=None, port=None, credentials=None, thread_pool=None, check_timeout=None, **kwargs) + + .. py:method:: is_ready(self, timeout=None) + + + .. py:method:: get_grpc_stub(self) + + + .. py:method:: get_stub(self) + + + .. py:method:: close(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.rst new file mode 100644 index 00000000..fb9869e9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable` +=================================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable.KiwoomOpenApiPlusServiceClientSideDynamicCallable + + + + +.. py:class:: KiwoomOpenApiPlusServiceClientSideDynamicCallable(stub, name) + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.rst new file mode 100644 index 00000000..1ad864aa --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.rst @@ -0,0 +1,31 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector` +=================================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector.KiwoomOpenApiPlusServiceClientSideSignalConnector + + + + +.. py:class:: KiwoomOpenApiPlusServiceClientSideSignalConnector(stub, name, executor) + + .. py:method:: shutdown(self) + + + .. py:method:: connect(self, callback) + + + .. py:method:: disconnect(self, callback) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.rst new file mode 100644 index 00000000..0140b97c --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.rst @@ -0,0 +1,421 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper` +=========================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubCoreWrapper + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubExtendedWrapper + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubWrapper + + + + +.. py:class:: KiwoomOpenApiPlusServiceClientStubCoreWrapper(stub, executor) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetUniversalMixin` + + KiwoomOpenApiPlusServiceServicer 에서 구현되어 이후 Stub 을 통해 제공되는 + RPC 들을 클라이언트에서 좀 더 쉽게 사용하기 위한 래퍼 함수들을 제공합니다. + + .. py:attribute:: METHOD_NAMES + + + + + .. py:attribute:: EVENT_NAMES + + + + + .. py:method:: Call(self, name, *args) + + 임의의 함수 호출을 위한 RPC 입니다. + + 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 + 호출결과를 응답 메시지를 통해 전달합니다. + + 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. + + + .. py:method:: LoginCall(self, credentials=None) + + 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. + + CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: TransactionCall(self, rqname, trcode, scrno, inputs, stop_condition=None) + + TR 요청에 해당하는 RPC 입니다. + + CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. + + 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 + 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. + + 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 + 내부적으로 호출됩니다. + + 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 + 대기시간이 발생할 수 있습니다. + + 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. + 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, + TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. + + + .. py:method:: OrderCall(self, rqname, scrno, account, order_type, code, quantity, price, quote_type, original_order_no=None) + + 주문 요청에 해당하는 RPC 입니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 + 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. + + 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. + 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. + + 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. + + 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. + + 거래 구분: + - 00: 지정가 + - 03: 시장가 + - 05: 조건부지정가 + - 06: 최유리지정가 + - 07: 최우선지정가 + - 10: 지정가IOC + - 13: 시장가IOC + - 16: 최유리IOC + - 20: 지정가FOK + - 23: 시장가FOK + - 26: 최유리FOK + - 61: 장전시간외종가 + - 62: 시간외단일가매매 + - 81: 장후시간외종가 + + ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + + 주문 유형: + - 1: 신규매수 + - 2: 신규매도 + - 3: 매수취소 + - 4: 매도취소 + - 5: 매수정정 + - 6: 매도정정 + + :param rqname: 사용자 구분 요청명 + :type rqname: str + :param scrno: 화면번호 (4자리) + :type scrno: str + :param account: 계좌번호 (10자리) + :type account: str + :param order_type: 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) + :type order_type: int + :param code: 종목코드 (6자리) + :type code: str + :param quantity: 주문수량 + :type quantity: int + :param price: 주문단가 + :type price: int + :param quote_type: 거래구분 (혹은 호가구분) + :type quote_type: str + :param original_order_no: 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. + :type original_order_no: str + + + .. py:method:: RealCall(self, scrno, codes, fids, opt_type=None, infer_fids=False, readable_names=False, fast_parse=False) + + 실시간 데이터 요청에 해당하는 RPC 입니다. + + SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 + 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. + + 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 + 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. + 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. + + + .. py:method:: LoadConditionCall(self) + + 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. + + GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: ConditionCall(self, scrno, condition_name, condition_index, search_type, with_info=False, is_future_option=False, request_name=None) + + 조건검색 기능에 해당하는 RPC 입니다. + + SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 + 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: SetLogLevel(self, level, logger='') + + 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. + + + .. py:method:: LoadCondition(self) + + 조건검색 관련 조건식을 불러옵니다. + + + .. py:method:: IsConditionLoaded(self) + + 조건식이 로드 되었는지 여부를 반환합니다. + + + .. py:method:: EnsureConditionLoaded(self, force=False) + + 조건식이 로드됨을 보장하도록 합니다. + + 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. + 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. + + + .. py:method:: RateLimitedCommRqData(self, rqname, trcode, prevnext, scrno, inputs=None) + + CommRqData() 와 동일하지만 호출제한 회피를 위한 함수입니다. + 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. + + + .. py:method:: RateLimitedSendCondition(self, scrno, condition_name, condition_index, search_type) + + SendCondition() 과 동일하지만 호출제한 회피를 위한 함수입니다. + 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. + + + +.. py:class:: KiwoomOpenApiPlusServiceClientStubExtendedWrapper(stub, executor) + + Bases: :py:obj:`KiwoomOpenApiPlusServiceClientStubCoreWrapper`, :py:obj:`koapy.utils.logging.Logging.Logging` + + 제공되는 RPC 들을 활용한 여러 사용 케이스들을 구현합니다. + + .. py:method:: GetStockBasicInfoAsDict(self, code, rqname=None, scrno=None) + + 주식 종목의 기본정보를 딕셔너리 형태로 반환합니다. + + TR: OPT10001 + + + .. py:method:: GetStockBasicInfoAsSeries(self, code, rqname=None, scrno=None) + + 주식 종목의 기본정보를 pd.Series 형태로 반환합니다. + + TR: OPT10001 + + + .. py:method:: GetStockQuoteInfoAsDataFrame(self, codes=None, rqname=None, scrno=None) + + 복수개의 주식 종목들의 기본정보를 pd.DataFrame 형태로 반환합니다. + + TR: OPTKWFID + + + .. py:method:: GetTickStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 틱 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10079 + + + .. py:method:: GetMinuteStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 분 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10080 + + + .. py:method:: GetDailyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 일 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10081 + + + .. py:method:: GetWeeklyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 주 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10082 + + + .. py:method:: GetMonthlyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 월 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10083 + + + .. py:method:: GetYearlyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None) + + 년 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. + + TR: OPT10094 + + + .. py:method:: GetDepositInfo(self, account_no, lookup_type=None, with_multi=False, rqname=None, scrno=None) + + 계좌의 예수금 정보를 반환합니다. + + TR: OPW00001 + + 조회구분 = 3:추정조회, 2:일반조회 + + + .. py:method:: GetStockQuotes(self, code, rqname=None, scrno=None) + + 주식의 호가정보를 반환합니다. + + TR: OPT10004 + + + .. py:method:: GetOrderLogAsDataFrame1(self, account_no, order_type=None, status_type=None, code=None, rqname=None, scrno=None) + + 미체결 주문 정보를 반환합니다. + + TR: OPT10075 + + 계좌번호 = 전문 조회할 보유계좌번호 + 전체종목구분 = 0:전체, 1:종목 + 매매구분 = 0:전체, 1:매도, 2:매수 + 종목코드 = 전문 조회할 종목코드 + 체결구분 = 0:전체, 2:체결, 1:미체결 + + + .. py:method:: GetOrderLogAsDataFrame2(self, account_no, order_type=None, status_type=None, code=None, order_no=None, rqname=None, scrno=None) + + 주문 체결 정보를 반환합니다. + + TR: OPT10076 + + 종목코드 = 전문 조회할 종목코드 + 조회구분 = 0:전체, 1:종목 + 매도수구분 = 0:전체, 1:매도, 2:매수 + 계좌번호 = 전문 조회할 보유계좌번호 + 비밀번호 = 사용안함(공백) + 주문번호 = 조회할 주문번호 + 체결구분 = 0:전체, 2:체결, 1:미체결 + + + .. py:method:: GetOrderLogAsDataFrame3(self, account_no, date=None, sort_type=None, asset_type=None, order_type=None, code=None, starting_order_no=None, rqname=None, scrno=None) + + 계좌별 주문 체결 내역을 반환합니다. + + TR: OPW00007 + + 주문일자 = YYYYMMDD (20170101 연도4자리, 월 2자리, 일 2자리 형식) + 계좌번호 = 전문 조회할 보유계좌번호 + 비밀번호 = 사용안함(공백) + 비밀번호입력매체구분 = 00 + 조회구분 = 1:주문순, 2:역순, 3:미체결, 4:체결내역만 + 주식채권구분 = 0:전체, 1:주식, 2:채권 + 매도수구분 = 0:전체, 1:매도, 2:매수 + 종목코드 + 시작주문번호 + + + .. py:method:: GetAccountRateOfReturnAsDataFrame(self, account_no, rqname=None, scrno=None) + + 계좌별 수익률 정보를 반환합니다. + + TR: OPT10085 + + + .. py:method:: GetAccountEvaluationStatusAsSeriesAndDataFrame(self, account_no, include_delisted=True, rqname=None, scrno=None) + + 계좌의 평가 현황 정보를 반환합니다. + + TR: OPW00004 + + + .. py:method:: GetAccountExecutionBalanceAsSeriesAndDataFrame(self, account_no, rqname=None, scrno=None) + + 계좌의 체결 잔고 정보를 반환합니다. + + TR: OPW00005 + + 모의투자에서는 지원하지 않는 TR 입니다. + + + .. py:method:: GetAccountEvaluationBalanceAsSeriesAndDataFrame(self, account_no, lookup_type=None, rqname=None, scrno=None) + + 계좌의 평가 잔고 내역 정보를 반환합니다. + + TR: OPW00018 + + 조회구분 = 1:합산, 2:개별 + + [ 주의 ] + "수익률%" 데이터는 모의투자에서는 소숫점표현, 실거래서버에서는 소숫점으로 변환 필요 합니다. + + + .. py:method:: GetMarketPriceInfo(self, code, rqname=None, scrno=None) + + 종목의 시세표성 정보를 반환합니다. + + TR: OPT10007 + + + .. py:method:: GetRealDataForCodesAsStream(self, codes, fids=None, opt_type=None, screen_no=None, infer_fids=False, readable_names=False, fast_parse=False) + + 실시간 데이터를 요청하고 스트림 형태로 반환받습니다. + + + .. py:method:: GetCodeListByCondition(self, condition_name, condition_index=None, with_info=False, is_future_option=False, request_name=None, screen_no=None) + + 주어진 조건식으로 조건검색을 수행하고 + 검색된 종목의 종목코드를 리스트로 반환받습니다. + + 파라미터 중 with_info 가 True 로 설정된 경우, + 검색된 종목들에 대한 기본 정보도 추가로 같이 반환됩니다. + + + .. py:method:: GetCodeListByConditionAsStream(self, condition_name, condition_index=None, with_info=False, is_future_option=False, request_name=None, screen_no=None, old_behavior=False) + + 주어진 조건식을 실시간 조건검색으로 등록합니다. + 이후 발생하는 이벤트들을 스트림 형태로 제공합니다. + + 최초 검색결과는 OnReceiveTrCondition() 이벤트로 반환되며 + 이후 종목의 추가/제외는 OnReceiveRealCondition() 이벤트로 반환됩니다. + + 만약 with_info 가 True 로 설정된 경우, + 검색된 종목마다 추가적인 정보가 OnReceiveTrData() 이벤트를 통해 반환됩니다. + + + +.. py:class:: KiwoomOpenApiPlusServiceClientStubWrapper(stub, executor) + + Bases: :py:obj:`KiwoomOpenApiPlusServiceClientStubExtendedWrapper` + + KiwoomOpenApiPlusServiceClientStubCoreWrapper, KiwoomOpenApiPlusServiceClientStubExtendedWrapper 의 구현 및 + KiwoomOpenApiPlusQAxWidgetUniversalMixin 의 구현들까지 최종적으로 포함된 + KiwoomOpenApiPlusServiceClientStub 객체를 위한 Mixin 래퍼 클래스 입니다. + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.rst new file mode 100644 index 00000000..97026411 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.rst @@ -0,0 +1,26 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils` +====================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils.convert_arguments_from_protobuf_to_python + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils.convert_arguments_from_python_to_protobuf + + + +.. py:function:: convert_arguments_from_protobuf_to_python(arguments) + + +.. py:function:: convert_arguments_from_python_to_protobuf(arguments, arguments_message) + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.rst new file mode 100644 index 00000000..4845744d --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.rst @@ -0,0 +1,45 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer` +================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer.KiwoomOpenApiPlusServiceServer + + + + +.. py:class:: KiwoomOpenApiPlusServiceServer(control, host=None, port=None, credentials=None, **kwargs) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: reinitialize_server(self) + + + .. py:method:: get_host(self) + + + .. py:method:: get_port(self) + + + .. py:method:: start(self) + + + .. py:method:: wait_for_termination(self, timeout=None) + + + .. py:method:: is_running(self) + + + .. py:method:: stop(self, grace=None) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.rst new file mode 100644 index 00000000..597ac0f5 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.rst @@ -0,0 +1,195 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer` +================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer.KiwoomOpenApiPlusServiceServicer + + + + +.. py:class:: KiwoomOpenApiPlusServiceServicer(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer` + + KiwoomOpenApiPlusService RPC 의 구현체 입니다. + + .. py:method:: control(self) + :property: + + + .. py:method:: screen_manager(self) + :property: + + + .. py:method:: Call(self, request, context) + + 임의의 함수 호출을 위한 RPC 입니다. + + 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 + 호출결과를 응답 메시지를 통해 전달합니다. + + 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. + + + .. py:method:: Listen(self, request, context) + + 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. + + 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. + 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. + + 서버측의 이벤트 핸들러 함수는 해당 이벤트를 클라이언트에 전송한 이후 즉시 종료됩니다. + + + .. py:method:: BidirectionalListen(self, request_iterator, context) + + 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. + + 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. + 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. + + 앞선 Listen() RPC 와 다르게 해당 RPC 는 이벤트 발생시 서버측에서는 이벤트 내용을 응답 메시지로 전달한 다음 + 다시 클라이언트 측에서 ACK 요청을 줄 때 까지 서버측 이벤트 핸들러 함수 내에서 대기합니다. + 따라서 클라이언트는 서버측 이벤트 핸들러 함수 컨텍스트 내에서 이벤트를 처리할 수 있고 + 처리를 완료하면 다시 서버측으로 ACK 요청을 보내 서버측 이벤트 핸들러가 완료될 수 있도록 해야 합니다. + + + .. py:method:: LoginCall(self, request, context) + + 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. + + CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: TransactionCall(self, request, context) + + TR 요청에 해당하는 RPC 입니다. + + CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. + + 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 + 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. + + 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 + 내부적으로 호출됩니다. + + 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 + 대기시간이 발생할 수 있습니다. + + 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. + 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, + TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. + + + .. py:method:: OrderCall(self, request, context) + + 주문 요청에 해당하는 RPC 입니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 + 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. + + 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. + 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. + + 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. + + 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. + + + .. py:method:: RealCall(self, request, context) + + 실시간 데이터 요청에 해당하는 RPC 입니다. + + SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 + 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 + 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. + 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. + + 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 + 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. + 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. + + + .. py:method:: LoadConditionCall(self, request, context) + + 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. + + GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 + 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: ConditionCall(self, request, context) + + 조건검색 기능에 해당하는 RPC 입니다. + + SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 + 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. + + + .. py:method:: BidirectionalRealCall(self, request_iterator, context) + + 실시간 데이터 요청에 해당하는 RPC 입니다. + + 기존의 RealCall() RPC 는 최초 실시간 데이터 등록 이후 이벤트를 듣는 것만 가능했다면 + 새로운 BidirectionalRealCall() 에서는 최초 설정된 이벤트 스트림을 계속 유지하면서 + 신규 실시간 데이터 등록 혹은 해지를 추가로 요청해 반영할 수 있습니다. + + + .. py:method:: OrderListen(self, request, context) + + 주문 이벤트를 듣고 싶을때 사용할 수 있는 RPC 입니다. + + 기존의 OrderCall() RPC 는 특정 주문을 수행하고 해당 주문과 관련된 이벤트들만 반환했다면 + 해당 RPC 는 특정 주문 수행 없이 모든 주문관련 이벤트를 듣고 싶을때 사용할 수 있습니다. + + + .. py:method:: CustomListen(self, request, context) + + 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. + + 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, + 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. + + 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. + + + .. py:method:: CustomCallAndListen(self, request, context) + + 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. + + 앞선 CustomListen() 과의 차이점은 요청시 특정 함수를 최초 1회 호출하고 이후 들어오는 이벤트를 처리한다는 점입니다. + + 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, + 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. + + 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. + + + .. py:method:: SetLogLevel(self, request, context) + + 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.rst new file mode 100644 index 00000000..ba0d0774 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.rst @@ -0,0 +1,434 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2` +============================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2 + +.. autoapi-nested-parse:: + + Generated protocol buffer code. + + + +Module Contents +--------------- + +.. py:data:: DESCRIPTOR + + + + +.. py:data:: TransactionStopConditionCompartor + + + + +.. py:data:: LESS_THAN_OR_EQUAL_TO + :annotation: = 0 + + + +.. py:data:: LESS_THAN + :annotation: = 1 + + + +.. py:data:: GREATER_THAN_OR_EQUAL_TO + :annotation: = 2 + + + +.. py:data:: GREATER_THAN + :annotation: = 3 + + + +.. py:data:: EQUAL_TO + :annotation: = 4 + + + +.. py:data:: NOT_EQUAL_TO + :annotation: = 5 + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: enum_type + + + + +.. py:data:: containing_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: message_type + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: containing_oneof + + + + +.. py:data:: Argument + + + + +.. py:data:: CallRequest + + + + +.. py:data:: ReturnValue + + + + +.. py:data:: CallResponse + + + + +.. py:data:: ListenRequest + + + + +.. py:data:: HandledRequest + + + + +.. py:data:: StopListenRequest + + + + +.. py:data:: BidirectionalListenRequest + + + + +.. py:data:: SingleData + + + + +.. py:data:: RepeatedString + + + + +.. py:data:: MultiData + + + + +.. py:data:: ListenResponse + + + + +.. py:data:: CallAndListenRequest + + + + +.. py:data:: CallAndListenResponse + + + + +.. py:data:: LoginCredentials + + + + +.. py:data:: LoginRequest + + + + +.. py:data:: RealRequestFlags + + + + +.. py:data:: RealRequest + + + + +.. py:data:: TransactionStopCondition + + + + +.. py:data:: TransactionRequest + + + + +.. py:data:: OrderSubscriptionTarget + + + + +.. py:data:: OrderRequest + + + + +.. py:data:: LoadConditionRequest + + + + +.. py:data:: ConditionRequestFlags + + + + +.. py:data:: ConditionRequest + + + + +.. py:data:: SetLogLevelRequest + + + + +.. py:data:: SetLogLevelResponse + + + + +.. py:data:: BidirectionalRealInitializeRequest + + + + +.. py:data:: BidirectionalRealRegisterRequest + + + + +.. py:data:: BidirectionalRealRemoveRequest + + + + +.. py:data:: BidirectionalRealStopRequest + + + + +.. py:data:: BidirectionalRealRequest + + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.rst new file mode 100644 index 00000000..abb14a6b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.rst @@ -0,0 +1,223 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc` +=================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc + +.. autoapi-nested-parse:: + + Client and server classes corresponding to protobuf-defined services. + + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceStub + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusService + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.add_KiwoomOpenApiPlusServiceServicer_to_server + + + +.. py:class:: KiwoomOpenApiPlusServiceStub(channel) + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + +.. py:class:: KiwoomOpenApiPlusServiceServicer + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + .. py:method:: Call(self, request, context) + + 1. rpcs for general function calls + + unary rpc for an arbitrary function call, + can invoke arbitrary function on the server side by giving its name and arguments, + currently only simple data types like str and int are supported for arguments and return values + + + .. py:method:: Listen(self, request, context) + + 2. rpcs for listening and handling events + + server streaming rpc usually for listening events, + server will simply send stream items to client whenever event that is being listened is triggered, + client can handle those events solely on its own on client side but there is no guarantee that it will be synced with the server, + which means that event handler on the server side will not wait for the client to finish handling each event + + + .. py:method:: BidirectionalListen(self, request_iterator, context) + + bidirectional streaming rpc usually for listening and handling events with proper callbacks, + server will send an stream item to client whenever an event is triggered and will wait for an client's ack, + so that following callbacks from the client can actually be processed inside the server's event handler context + + + .. py:method:: LoginCall(self, request, context) + + 3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns + + server streaming rpc for login/connect scenario, + would invoke Connect() and wait for OnEventConnect() event to test its success + + + .. py:method:: TransactionCall(self, request, context) + + server streaming rpc for general transaction requests, + would invoke CommRqData() with several SetInputValue()s for a transaction request, + would wait for OnReceiveTrData() events, + would handle those events to gather results by invoking GetRepeatCnt() and GetCommData() inside, + might do additional CommRqData() and SetInputValue() inside event handler for possible consecutive lookups + + + .. py:method:: OrderCall(self, request, context) + + server streaming rpc for making orders (buy/sell + update/cancel), + would invoke SendOrder() for submitting an order, + would wait for OnReceiveTrData() and OnReceiveChejanData() events to track its progress + + + .. py:method:: RealCall(self, request, context) + + server streaming rpc for listening realtime data events, + certain transaction requests would also register some realtime data to be sent, + but usually would just call SetRealReg() to register desired realtime data to listen explicitly, + and would call SetRealRemove() to unregister them after done using, + would wait for OnReceiveRealData() events + + + .. py:method:: LoadConditionCall(self, request, context) + + server streaming rpc for loading condition settings for conditioned search, + would call GetConditionLoad() and wait for OnReceiveConditionVer() event to test its success + + + .. py:method:: ConditionCall(self, request, context) + + server streaming rpc for conditioned search (serching stocks with serveral conditions), + would call SendCondition() and wait for OnReceiveTrCondition() or OnReceiveRealCondition() based on its requested type + + + .. py:method:: BidirectionalRealCall(self, request_iterator, context) + + 4. rpcs for more complex use cases based on the previously categorized simple cases above + + bidirectional streaming rpc for listening realtime data events, + with capability of managing observation pool (what stocks, what fields to listen to) online, + those management requests would be sent over the client streaming line, + and ordinary realtime data events would be sent over the server streaming line + + + .. py:method:: OrderListen(self, request, context) + + server streaming rpc for just listening order events (without submiting any order request compared to the simple case), + this is one-sided streaming rpc (server streaming rpc) like Listen() rpc, + so server would just send stream items with no consideration on coordination with its client + + + .. py:method:: CustomListen(self, request, context) + + 5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) + + pretty much similar to server streaming Listen() rpc, + but event handler would be instantiated dynamically based on the code given through the request + + + .. py:method:: CustomCallAndListen(self, request, context) + + pretty much similar to server streaming XXXCall() rpcs (or even Call() rpc), + but event handler would be instantiated dynamically based on the code given through the request + + + .. py:method:: SetLogLevel(self, request, context) + + 6. rpcs for other mics scenarios + + would update log level of process that this grpc server lives + + + +.. py:function:: add_KiwoomOpenApiPlusServiceServicer_to_server(servicer, server) + + +.. py:class:: KiwoomOpenApiPlusService + + Bases: :py:obj:`object` + + Missing associated documentation comment in .proto file. + + .. py:method:: Call(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: Listen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: BidirectionalListen(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: LoginCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: TransactionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: OrderCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: RealCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: LoadConditionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: ConditionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: BidirectionalRealCall(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: OrderListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: CustomListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: CustomCallAndListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + .. py:method:: SetLogLevel(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None) + :staticmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.rst new file mode 100644 index 00000000..a14f7fa9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler` +============================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler.KiwoomOpenApiPlusConditionEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusConditionEventHandler(control, request, context, screen_manager) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.rst new file mode 100644 index 00000000..37f29f2c --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.rst @@ -0,0 +1,28 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc` +============================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc + + + + +.. py:class:: KiwoomOpenApiPlusEventHandlerForGrpc(control, context) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler` + + .. py:method:: context(self) + :property: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.rst new file mode 100644 index 00000000..cfb649c1 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.rst @@ -0,0 +1,141 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers` +====================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazyAllEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerAllEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusAllEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazySomeEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerSomeEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusSomeEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusSomeBidirectionalEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusLazyAllEventHandler(control, context) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + +.. py:class:: KiwoomOpenApiPlusEagerAllEventHandler(control, context) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + +.. py:class:: KiwoomOpenApiPlusAllEventHandler(control, context) + + Bases: :py:obj:`KiwoomOpenApiPlusEagerAllEventHandler` + + +.. py:class:: KiwoomOpenApiPlusLazySomeEventHandler(control, request, context) + + Bases: :py:obj:`KiwoomOpenApiPlusLazyAllEventHandler` + + .. py:method:: slots(self) + + + +.. py:class:: KiwoomOpenApiPlusEagerSomeEventHandler(control, request, context) + + Bases: :py:obj:`KiwoomOpenApiPlusEagerAllEventHandler` + + .. py:method:: slots(self) + + + +.. py:class:: KiwoomOpenApiPlusSomeEventHandler(control, request, context) + + Bases: :py:obj:`KiwoomOpenApiPlusEagerSomeEventHandler` + + +.. py:class:: KiwoomOpenApiPlusSomeBidirectionalEventHandler(control, request_iterator, context) + + Bases: :py:obj:`KiwoomOpenApiPlusLazySomeEventHandler` + + .. py:method:: await_handled(self) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.rst new file mode 100644 index 00000000..418872ed --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler` +========================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler.KiwoomOpenApiPlusKwTrEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusKwTrEventHandler(control, request, context, screen_manager) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.rst new file mode 100644 index 00000000..df48707b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler` +================================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler.KiwoomOpenApiPlusLoadConditionEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusLoadConditionEventHandler(control, context, request) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.rst new file mode 100644 index 00000000..44f8ca50 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.rst @@ -0,0 +1,61 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler` +============================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusLoggingEventHandler(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + [OnReceiveMsg()이벤트] + + OnReceiveMsg( + BSTR sScrNo, // 화면번호 + BSTR sRQName, // 사용자 구분명 + BSTR sTrCode, // TR이름 + BSTR sMsg // 서버에서 전달하는 메시지 + ) + + 서버통신 후 수신한 메시지를 알려줍니다. + 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 + 이 코드번호로 분류하시면 안됩니다. + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index) + + + .. py:method:: OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext) + + + .. py:method:: OnReceiveConditionVer(self, ret, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.rst new file mode 100644 index 00000000..c31360a1 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler` +========================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler.KiwoomOpenApiPlusLoginEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusLoginEventHandler(control, request, context) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc` + + .. py:method:: on_enter(self) + + + .. py:method:: OnEventConnect(self, errcode) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.rst new file mode 100644 index 00000000..73464766 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.rst @@ -0,0 +1,69 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler` +========================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusBaseOrderEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusAllOrderEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusOrderEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusBaseOrderEventHandler(control, context) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: ResponseForOnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: ResponseForOnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + + + .. py:method:: ResponseForOnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + +.. py:class:: KiwoomOpenApiPlusAllOrderEventHandler(control, context) + + Bases: :py:obj:`KiwoomOpenApiPlusBaseOrderEventHandler` + + +.. py:class:: KiwoomOpenApiPlusOrderEventHandler(control, request, context, screen_manager) + + Bases: :py:obj:`KiwoomOpenApiPlusBaseOrderEventHandler`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.rst new file mode 100644 index 00000000..f39fbb05 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.rst @@ -0,0 +1,69 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler` +========================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusRealEventHandler + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusBidirectionalRealEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusRealEventHandler(control, request, context, screen_manager) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnEventConnect(self, errcode) + + + +.. py:class:: KiwoomOpenApiPlusBidirectionalRealEventHandler(control, request_iterator, context, screen_manager) + + Bases: :py:obj:`KiwoomOpenApiPlusRealEventHandler`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: register_code(self, code, fid_list=None) + + + .. py:method:: remove_code(self, code) + + + .. py:method:: remove_all_codes(self) + + + .. py:method:: remove_all_screens(self) + + + .. py:method:: consume_request_iterator(self) + + + .. py:method:: stop_request_iterator_consumer(self) + + + .. py:method:: start_request_iterator_consumer(self) + + + .. py:method:: on_enter(self) + + + .. py:method:: on_exit(self, exc_type=None, exc_value=None, traceback=None) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.rst new file mode 100644 index 00000000..6421bd21 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler` +======================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler.KiwoomOpenApiPlusTrEventHandler + + + + +.. py:class:: KiwoomOpenApiPlusTrEventHandler(control, request, context, screen_manager) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: on_enter(self) + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg) + + + .. py:method:: OnEventConnect(self, errcode) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.rst new file mode 100644 index 00000000..b537353a --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.event` +======================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.event + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiPlusConditionEventHandler/index.rst + KiwoomOpenApiPlusEventHandlerForGrpc/index.rst + KiwoomOpenApiPlusEventHandlers/index.rst + KiwoomOpenApiPlusKwTrEventHandler/index.rst + KiwoomOpenApiPlusLoadConditionEventHandler/index.rst + KiwoomOpenApiPlusLoggingEventHandler/index.rst + KiwoomOpenApiPlusLoginEventHandler/index.rst + KiwoomOpenApiPlusOrderEventHandler/index.rst + KiwoomOpenApiPlusRealEventHandler/index.rst + KiwoomOpenApiPlusTrEventHandler/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.rst new file mode 100644 index 00000000..76b9a2f9 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.rst @@ -0,0 +1,33 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc` +================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + event/index.rst + tools/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiPlusServiceClient/index.rst + KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.rst + KiwoomOpenApiPlusServiceClientSideSignalConnector/index.rst + KiwoomOpenApiPlusServiceClientStubWrapper/index.rst + KiwoomOpenApiPlusServiceMessageUtils/index.rst + KiwoomOpenApiPlusServiceServer/index.rst + KiwoomOpenApiPlusServiceServicer/index.rst + KiwoomOpenApiPlusService_pb2/index.rst + KiwoomOpenApiPlusService_pb2_grpc/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.rst new file mode 100644 index 00000000..8e32dd50 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto` +===================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto.compile_proto + + + +.. py:function:: compile_proto() + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.rst new file mode 100644 index 00000000..5eb0b0b0 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.grpc.tools` +======================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.grpc.tools + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + compile_proto/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/index.rst new file mode 100644 index 00000000..1679686f --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus` +============================================ + +.. py:module:: koapy.backend.kiwoom_open_api_plus + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + core/index.rst + grpc/index.rst + pyside2/index.rst + utils/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.rst new file mode 100644 index 00000000..b9bd4761 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.rst @@ -0,0 +1,70 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler` +=================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.DialogToHandle + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogToHandle + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogHandler + + + + +.. py:class:: DialogToHandle + + .. py:method:: should_handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) -> bool + + + .. py:method:: handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) + + + .. py:method:: handle_if_needed(self, dialog: koapy.compat.pywinauto.WindowSpecification) + + + +.. py:class:: KiwoomOpenApiPlusDialogToHandle(title: Optional[str] = None, time: Optional[datetime.time] = None, body: Optional[str] = None, app: Optional[koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication] = None, restart_type: Optional[koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.RestartType] = None) + + Bases: :py:obj:`DialogToHandle`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: should_handle_by_title(cls, dialog: koapy.compat.pywinauto.WindowSpecification, title: str) + :classmethod: + + + .. py:method:: handle_by_clicking_button(cls, dialog: koapy.compat.pywinauto.WindowSpecification) + :classmethod: + + + .. py:method:: handle_by_emiting_should_restart_signal(cls, app: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication, restart_type: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.RestartType) + :classmethod: + + + .. py:method:: to_specification(self) -> koapy.compat.pywinauto.WindowSpecification + + + .. py:method:: should_handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) -> bool + + + .. py:method:: handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) + + + .. py:method:: handle_if_needed(self, dialog: koapy.compat.pywinauto.WindowSpecification) + + + +.. py:class:: KiwoomOpenApiPlusDialogHandler(app: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler.QDialogHandler` + + .. py:method:: onReadyDialog(self, dialog: koapy.compat.pywinauto.WindowSpecification) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.rst new file mode 100644 index 00000000..59fe8a55 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.rst @@ -0,0 +1,169 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication` +======================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplicationArgumentParser + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusServerApplicationProcess + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusServerApplicationSubprocess + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication + + + + +.. py:class:: KiwoomOpenApiPlusManagerApplicationArgumentParser + + Bases: :py:obj:`koapy.cli.extensions.parser.ArgumentParser` + + .. py:method:: parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace + + + .. py:method:: parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> Tuple[argparse.Namespace, List[str]] + + + +.. py:class:: KiwoomOpenApiPlusServerApplicationProcess(args, parent=None) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QProcess` + + +.. py:class:: KiwoomOpenApiPlusServerApplicationSubprocess(args, parent=None) + + .. py:method:: start(self) + + + .. py:method:: waitForStarted(self, msecs: int = 30000) -> bool + + + .. py:method:: close(self) + + + .. py:method:: waitForFinished(self, msecs: int = 30000) -> bool + + + +.. py:class:: KiwoomOpenApiPlusManagerApplication(args=()) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging` + + .. py:class:: ConnectionStatus + + Bases: :py:obj:`enum.Enum` + + Generic enumeration. + + Derive from this class to define new enumerations. + + .. py:attribute:: DISCONNECTED + :annotation: = 1 + + + + .. py:attribute:: CONNECTED + :annotation: = 2 + + + + + .. py:class:: ServerType + + Bases: :py:obj:`enum.Enum` + + Generic enumeration. + + Derive from this class to define new enumerations. + + .. py:attribute:: SIMULATION + :annotation: = 1 + + + + .. py:attribute:: REAL + :annotation: = 2 + + + + .. py:attribute:: UNKNOWN + :annotation: = 3 + + + + + .. py:class:: RestartType + + Bases: :py:obj:`enum.Enum` + + Generic enumeration. + + Derive from this class to define new enumerations. + + .. py:attribute:: NO_RESTART + :annotation: = 1 + + + + .. py:attribute:: RESTART_ONLY + :annotation: = 2 + + + + .. py:attribute:: RESTART_AND_RESTORE + :annotation: = 3 + + + + .. py:attribute:: RESTART_AND_CONNECT + :annotation: = 4 + + + + .. py:attribute:: RESTART_WITH_UPDATE + :annotation: = 5 + + + + .. py:attribute:: RESTART_WITH_UPDATE_AND_RESTORE + :annotation: = 6 + + + + .. py:attribute:: RESTART_WITH_UPDATE_AND_CONNECT + :annotation: = 7 + + + + + .. py:attribute:: shouldRestart + + + + + .. py:method:: close(self) + + + .. py:method:: exec_(self) + + + .. py:method:: exit(self, return_code=0) + + + .. py:method:: restart(self, restart_type: Optional[RestartType] = None) + + + .. py:method:: execAndExit(self) + + + .. py:method:: main(cls, args=None) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.rst new file mode 100644 index 00000000..6bde00a1 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.rst @@ -0,0 +1,92 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication` +======================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplicationArgumentParser + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplication + + + + +.. py:class:: KiwoomOpenApiPlusServerApplicationArgumentParser + + Bases: :py:obj:`koapy.cli.extensions.parser.ArgumentParser` + + .. py:method:: parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace + + + .. py:method:: parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> Tuple[argparse.Namespace, List[str]] + + + +.. py:class:: KiwoomOpenApiPlusServerApplication(args=()) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging` + + .. py:class:: ConnectionStatus + + Bases: :py:obj:`enum.Enum` + + Generic enumeration. + + Derive from this class to define new enumerations. + + .. py:attribute:: DISCONNECTED + :annotation: = 1 + + + + .. py:attribute:: CONNECTED + :annotation: = 2 + + + + + .. py:class:: ServerType + + Bases: :py:obj:`enum.Enum` + + Generic enumeration. + + Derive from this class to define new enumerations. + + .. py:attribute:: SIMULATION + :annotation: = 1 + + + + .. py:attribute:: REAL + :annotation: = 2 + + + + .. py:attribute:: UNKNOWN + :annotation: = 3 + + + + + .. py:method:: exec_(self) + + + .. py:method:: exit(self, return_code=0) + + + .. py:method:: execAndExit(self) + + + .. py:method:: main(cls, args=None) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.rst new file mode 100644 index 00000000..9827fad6 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler` +=================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler.KiwoomOpenApiPlusSignalHandler + + + + +.. py:class:: KiwoomOpenApiPlusSignalHandler(app, parent=None) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler.QSignalHandler` + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.rst new file mode 100644 index 00000000..02927967 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.pyside2` +==================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.pyside2 + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiPlusDialogHandler/index.rst + KiwoomOpenApiPlusManagerApplication/index.rst + KiwoomOpenApiPlusServerApplication/index.rst + KiwoomOpenApiPlusSignalHandler/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.rst new file mode 100644 index 00000000..e83e2ba2 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.rst @@ -0,0 +1,27 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous` +======================================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous.PipeableMultiThreadedRendezvous + + + + +.. py:class:: PipeableMultiThreadedRendezvous(rendezvous, iterator=None) + + Bases: :py:obj:`collections.abc.Iterator` + + .. py:method:: pipe(self, func) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.rst new file mode 100644 index 00000000..0153e721 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.grpc` +======================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.grpc + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + PipeableMultiThreadedRendezvous/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.rst new file mode 100644 index 00000000..86092694 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.rst @@ -0,0 +1,27 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils` +================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + grpc/index.rst + pyside2/index.rst + queue/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + list_conversion/index.rst + module_path/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.rst new file mode 100644 index 00000000..1a2c0cdf --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.list_conversion` +================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.list_conversion + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.list_conversion.string_to_list + koapy.backend.kiwoom_open_api_plus.utils.list_conversion.list_to_string + koapy.backend.kiwoom_open_api_plus.utils.list_conversion.convert_list_arguments + + + +.. py:function:: string_to_list(s, sep=';') + + +.. py:function:: list_to_string(l, sep=';') + + +.. py:function:: convert_list_arguments(*indices) + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.rst new file mode 100644 index 00000000..1eb2b56a --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.module_path` +============================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.module_path + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.module_path.GetAPIModulePath + + + +.. py:function:: GetAPIModulePath() -> pathlib.Path + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.rst new file mode 100644 index 00000000..e95ea5f8 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.rst @@ -0,0 +1,50 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler` +========================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler.QDialogHandler + + + + +.. py:class:: QDialogHandler(specifications: Optional[Sequence[koapy.compat.pywinauto.WindowSpecification]] = None, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging` + + .. py:attribute:: readyDialog + + + + + .. py:attribute:: notReadyDialog + + + + + .. py:method:: from_titles(cls, titles: Sequence[str], allow_magic_lookup: bool = False) + :classmethod: + + + .. py:method:: get_text_of_dialog(self, dialog: koapy.compat.pywinauto.WindowSpecification, default: Optional[str] = None) + + + .. py:method:: run(self) + + + .. py:method:: stop(self) + + + .. py:method:: wait_for_termination(self, timeout=None) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.rst new file mode 100644 index 00000000..b4000916 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.rst @@ -0,0 +1,56 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler` +========================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler.QSignalHandler + + + + +.. py:class:: QSignalHandler(signals: Iterable[signal.Signals], parent: Optional[koapy.compat.pyside2.QtCore.QObject]) QSignalHandler(parent: Optional[koapy.compat.pyside2.QtCore.QObject]) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLogging` + + .. py:attribute:: signaled + + + + + .. py:method:: onReadyRead(self) + + + .. py:method:: emitSignal(self, signal, frame) + + + .. py:method:: setWakeUpFileDescriptor(self, descriptor, warn_on_full_buffer=True) + + + .. py:method:: restoreWakeUpFileDescrptor(self) + + + .. py:method:: setHandler(self, signal, handler) + + + .. py:method:: restoreHandler(self, signal, default=None) + + + .. py:method:: restoreAllHandlers(self) + + + .. py:method:: setAll(self) + + + .. py:method:: restoreAll(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst new file mode 100644 index 00000000..9b2ab330 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst @@ -0,0 +1,57 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor` +============================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutorRunnable + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutor + + + + +.. py:class:: QThreadPoolExecutorRunnable(future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Union[Tuple[Any], List[Any]], kwargs: Dict[str, Any]) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QRunnable` + + .. py:method:: run(self) + + + +.. py:class:: QThreadPoolExecutor(thread_pool: koapy.compat.pyside2.QtCore.QThreadPool, parent: Optional[koapy.compat.pyside2.QtCore.QObject]) QThreadPoolExecutor(parent: Optional[koapy.compat.pyside2.QtCore.QObject]) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QObject`, :py:obj:`concurrent.futures.Executor` + + This is an abstract base class for concrete asynchronous executors. + + .. py:method:: submit(self, fn, *args, **kwargs) + + Submits a callable to be executed with the given arguments. + + Schedules the callable to be executed as fn(*args, **kwargs) and returns + a Future instance representing the execution of the callable. + + :returns: A Future representing the given call. + + + .. py:method:: shutdown(self, wait=True, cancel_futures=False) + + Clean-up the resources associated with the Executor. + + It is safe to call this method several times. Otherwise, no other + methods can be called after this one. + + :param wait: If True then shutdown will not return until all running + futures have finished executing and the resources used by the + executor have been reclaimed. + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.rst new file mode 100644 index 00000000..ba131b1e --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.rst @@ -0,0 +1,17 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.pyside2` +========================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.pyside2 + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + QDialogHandler/index.rst + QSignalHandler/index.rst + QThreadPoolExecutor/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.rst new file mode 100644 index 00000000..a747a292 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.rst @@ -0,0 +1,27 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator` +=================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator.QueueBasedBufferedIterator + + + + +.. py:class:: QueueBasedBufferedIterator(iterator, queue=None, maxsize=None) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: next(self, block=True, timeout=None) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.rst new file mode 100644 index 00000000..3dedec38 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.rst @@ -0,0 +1,67 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver` +=================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserverIterator + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserver + + + + +.. py:class:: QueueBasedIterableObserverIterator(queue, sentinel) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator` + + .. py:method:: next(self, block=True, timeout=None) + + + .. py:method:: head(self) + + + +.. py:class:: QueueBasedIterableObserver(queue=None, maxsize=None) + + Bases: :py:obj:`rx.core.typing.Observer` + + Observer abstract base class + + An Observer is the entity that receives all emissions of a subscribed + Observable. + + .. py:method:: queue(self) + :property: + + + .. py:method:: on_next(self, value) + + Notifies the observer of a new element in the sequence. + + :param value: The received element. + + + .. py:method:: on_error(self, error) + + Notifies the observer that an exception has occurred. + + :param error: The error that has occurred. + + + .. py:method:: on_completed(self) + + Notifies the observer of the end of the sequence. + + + .. py:method:: stop(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.rst new file mode 100644 index 00000000..755e20cc --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.rst @@ -0,0 +1,56 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator` +====================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.QueueIterator + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator + + + + +.. py:class:: QueueIterator(queue) + + .. py:method:: queue(self) + :property: + + + .. py:method:: next(self, block=True, timeout=None) + + + .. py:method:: next_nowait(self) + + + .. py:method:: has_next(self) + + + .. py:method:: stop(self) + + + .. py:method:: enable(self) + + + +.. py:class:: BufferedQueueIterator(queue) + + Bases: :py:obj:`QueueIterator` + + .. py:method:: next(self, block=True, timeout=None) + + + .. py:method:: has_next(self) + + + .. py:method:: head(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.rst new file mode 100644 index 00000000..352a869b --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.rst @@ -0,0 +1,17 @@ +:py:mod:`koapy.backend.kiwoom_open_api_plus.utils.queue` +======================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_plus.utils.queue + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + QueueBasedBufferedIterator/index.rst + QueueBasedIterableObserver/index.rst + QueueIterator/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.rst new file mode 100644 index 00000000..15d22daa --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.rst @@ -0,0 +1,25 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable` +============================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable.KiwoomOpenApiWDynamicCallable + + + + +.. py:class:: KiwoomOpenApiWDynamicCallable(control, name) + + .. py:method:: is_valid_return_type(self, result) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.rst new file mode 100644 index 00000000..510291ab --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEntrypoint` +======================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEntrypoint + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.rst new file mode 100644 index 00000000..bf572ceb --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.rst @@ -0,0 +1,243 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError` +================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError + + +Module Contents +--------------- + +.. py:exception:: KiwoomOpenApiWError(message=None) + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + .. py:method:: message(self) + :property: + + + .. py:method:: try_or_raise(cls, arg, message=None) + :classmethod: + + + .. py:method:: try_or_raise_boolean(cls, arg, message) + :classmethod: + + + +.. py:exception:: KiwoomOpenApiWNegativeReturnCodeError(code, message=None) + + Bases: :py:obj:`KiwoomOpenApiWError` + + Common base class for all non-exit exceptions. + + .. py:attribute:: OP_ERR_NONE + :annotation: = 0 + + + + .. py:attribute:: OP_ERR_NO_LOGIN + + + + + .. py:attribute:: OP_ERR_LOGIN + + + + + .. py:attribute:: OP_ERR_CONNECT + + + + + .. py:attribute:: OP_ERR_VERSION + + + + + .. py:attribute:: OP_ERR_TRCODE + + + + + .. py:attribute:: OP_ERR_NO_REGOPENAPI + + + + + .. py:attribute:: OP_ERR_SISE_OVERFLOW + + + + + .. py:attribute:: OP_ERR_ORDER_OVERFLOW + + + + + .. py:attribute:: OP_ERR_RQ_WRONG_INPUT + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_INPUT + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_ACCPWD + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_ACCNO + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_QTY200 + + + + + .. py:attribute:: OP_ERR_ORD_WRONG_QTY400 + + + + + .. py:attribute:: MSG_ERR_NONE + :annotation: = 정상처리 + + + + .. py:attribute:: MSG_ERR_NO_LOGIN + :annotation: = 미접속상태 + + + + .. py:attribute:: MSG_ERR_LOGIN + :annotation: = 로그인시 접속 실패 (아이피 오류 또는 접속정보 오류) + + + + .. py:attribute:: MSG_ERR_CONNECT + :annotation: = 서버 접속 실패 + + + + .. py:attribute:: MSG_ERR_VERSION + :annotation: = 버전처리가 실패하였습니다. + + + + .. py:attribute:: MSG_ERR_TRCODE + :annotation: = TrCode 가 존재하지 않습니다. + + + + .. py:attribute:: MSG_ERR_NO_REGOPENAPI + :annotation: = 해외OpenAPI 미신청 + + + + .. py:attribute:: MSG_ERR_SISE_OVERFLOW + :annotation: = 조회과부화 + + + + .. py:attribute:: MSG_ERR_ORDER_OVERFLOW + :annotation: = 주문과부화 + + + + .. py:attribute:: MSG_ERR_RQ_WRONG_INPUT + :annotation: = 조회입력값(명칭/누락) 오류 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_INPUT + :annotation: = 주문입력갑 오류 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_ACCPWD + :annotation: = 계좌비밀번호를 입력하십시오. + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_ACCNO + :annotation: = 타인 계좌를 사용할 수 없습니다. + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_QTY200 + :annotation: = 경고-주문수량 200개 초과 + + + + .. py:attribute:: MSG_ERR_ORD_WRONG_QTY400 + :annotation: = 제한-주문수량 400개 초과 + + + + .. py:attribute:: ERROR_MESSAGE_BY_CODE + + + + + .. py:method:: get_error_message_by_code(cls, code, default=None) + :classmethod: + + + .. py:method:: check_code_or_raise(cls, code) + :classmethod: + + + .. py:method:: wrap_to_check_code_or_raise(cls, func) + :classmethod: + + + .. py:method:: try_or_raise(cls, arg, message=None) + :classmethod: + + + .. py:method:: code(self) + :property: + + + +.. py:exception:: KiwoomOpenApiWBooleanReturnCodeError(code, message=None) + + Bases: :py:obj:`KiwoomOpenApiWError` + + Common base class for all non-exit exceptions. + + .. py:attribute:: OP_ERR_SUCCESS + :annotation: = 1 + + + + .. py:attribute:: OP_ERR_FAILURE + :annotation: = 0 + + + + .. py:method:: check_code_or_raise(cls, code, message=None) + :classmethod: + + + .. py:method:: wrap_to_check_code_or_raise(cls, func, message=None) + :classmethod: + + + .. py:method:: try_or_raise(cls, arg, message=None) + :classmethod: + + + .. py:method:: code(self) + :property: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.rst new file mode 100644 index 00000000..9b8ce590 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.rst @@ -0,0 +1,66 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler` +========================================================================= + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler.KiwoomOpenApiWEventHandler + + + + +.. py:class:: KiwoomOpenApiWEventHandler(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions.KiwoomOpenApiWEventHandlerFunctions` + + .. py:method:: control(self) + :property: + + + .. py:method:: observer(self) + :property: + + + .. py:method:: names(cls) + :classmethod: + + + .. py:method:: slots(self) + + + .. py:method:: connect(self) + + + .. py:method:: disconnect(self) + + + .. py:method:: on_enter(self) + + + .. py:method:: on_exit(self, exc_type=None, exc_value=None, traceback=None) + + + .. py:method:: add_callback(self, callback, *args, **kwargs) + + + .. py:method:: enter(self) + + + .. py:method:: exit(self, exc_type=None, exc_value=None, traceback=None) + + + .. py:method:: stop(self) + + + .. py:method:: close(self) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.rst new file mode 100644 index 00000000..dedc1009 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.rst @@ -0,0 +1,42 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions` +================================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions.KiwoomOpenApiWEventHandlerFunctions + + + + +.. py:class:: KiwoomOpenApiWEventHandlerFunctions + + .. py:method:: OnEventConnect(self, errcode) + :abstractmethod: + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + :abstractmethod: + + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext) + :abstractmethod: + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + :abstractmethod: + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + :abstractmethod: + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.rst new file mode 100644 index 00000000..8683c1da --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.rst @@ -0,0 +1,39 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler` +================================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler.KiwoomOpenApiWLoggingEventHandler + + + + +.. py:class:: KiwoomOpenApiWLoggingEventHandler(control) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler.KiwoomOpenApiWEventHandler`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext) + + + .. py:method:: OnReceiveRealData(self, code, realtype, realdata) + + + .. py:method:: OnReceiveMsg(self, scrnno, rqname, trcode, msg) + + + .. py:method:: OnReceiveChejanData(self, gubun, itemcnt, fidlist) + + + .. py:method:: OnEventConnect(self, errcode) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.rst new file mode 100644 index 00000000..e227e1b0 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.rst @@ -0,0 +1,45 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget` +====================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget.KiwoomOpenApiWQAxWidget + + + + +.. py:class:: KiwoomOpenApiWQAxWidget(*args, **kwargs) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging`, :py:obj:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin.KiwoomOpenApiWQAxWidgetMixin` + + .. py:attribute:: CLSID + :annotation: = {D1ACAB7D-A3AF-49E4-9004-C9E98344E17A} + + + + .. py:attribute:: METHOD_NAMES + + + + + .. py:attribute:: EVENT_NAMES + + + + + .. py:method:: changeEvent(self, event) + + + .. py:method:: closeEvent(self, event) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.rst new file mode 100644 index 00000000..3b09e488 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin` +=========================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin.KiwoomOpenApiWQAxWidgetMixin + + + + +.. py:class:: KiwoomOpenApiWQAxWidgetMixin + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.rst new file mode 100644 index 00000000..5a8bb699 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.rst @@ -0,0 +1,39 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector` +============================================================================ + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector.KiwoomOpenApiWSignalConnector + + + + +.. py:class:: KiwoomOpenApiWSignalConnector(name=None) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: is_valid_slot(self, slot) + + + .. py:method:: connect_to(self, control) + + + .. py:method:: connect(self, slot) + + + .. py:method:: disconnect(self, slot=None) + + + .. py:method:: call(self, *args, **kwargs) + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst new file mode 100644 index 00000000..dabd1a2f --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst @@ -0,0 +1,203 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature` +====================================================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWSignature + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWDispatchSignature + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWEventHandlerSignature + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.BuildOleItems + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.LoadDispatchSignatures + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.LoadEventHandlerSignatures + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.DISPATCH_SIGNATURES_BY_NAME + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.EVENT_HANDLER_SIGNATURES_BY_NAME + + +.. py:function:: BuildOleItems(clsid) + + +.. py:class:: KiwoomOpenApiWSignature(name, parameters=None, return_annotation=Signature.empty, entry=None) + + Bases: :py:obj:`inspect.Signature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: MODULE_CLSID + :annotation: = {1F8A15ED-A979-488F-9694-1EDA98188FFC} + + + + .. py:attribute:: OLE_ITEMS + + + + + .. py:attribute:: DISPATCH_CLSID + :annotation: = {85B07632-4F84-4CEF-991D-C79DE781363D} + + + + .. py:attribute:: EVENT_CLSID + :annotation: = {952B31F8-06FD-4D5A-A021-5FF57F5030AE} + + + + .. py:attribute:: PYTHONTYPE_TO_QTTYPE + + + + + .. py:attribute:: COMTYPE_TO_PYTHONTYPE + + + + + .. py:method:: name(self) + :property: + + + .. py:method:: to_pyside2_function_prototype(self) + + + .. py:method:: to_pyside2_event_signal(self) + + + +.. py:class:: KiwoomOpenApiWDispatchSignature(name, parameters=None, return_annotation=Signature.empty, entry=None) + + Bases: :py:obj:`KiwoomOpenApiWSignature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: DISPATCH_SIGNATURES_BY_NAME + + + + + .. py:method:: from_name(cls, name) + :classmethod: + + + .. py:method:: names(cls) + :classmethod: + + + +.. py:function:: LoadDispatchSignatures(oleItems, clsId) + + +.. py:data:: DISPATCH_SIGNATURES_BY_NAME + + + + +.. py:class:: KiwoomOpenApiWEventHandlerSignature(name, parameters=None, return_annotation=Signature.empty, entry=None) + + Bases: :py:obj:`KiwoomOpenApiWSignature` + + A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is set to `Signature.empty`. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + + .. py:attribute:: EVENT_HANDLER_SIGNATURES_BY_NAME + + + + + .. py:method:: from_name(cls, name) + :classmethod: + + + .. py:method:: names(cls) + :classmethod: + + + +.. py:function:: LoadEventHandlerSignatures(oleItems, clsId) + + +.. py:data:: EVENT_HANDLER_SIGNATURES_BY_NAME + + + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/index.rst new file mode 100644 index 00000000..6b2ef6b7 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/core/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w.core` +============================================== + +.. py:module:: koapy.backend.kiwoom_open_api_w.core + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiWDynamicCallable/index.rst + KiwoomOpenApiWEntrypoint/index.rst + KiwoomOpenApiWError/index.rst + KiwoomOpenApiWEventHandler/index.rst + KiwoomOpenApiWEventHandlerFunctions/index.rst + KiwoomOpenApiWLoggingEventHandler/index.rst + KiwoomOpenApiWQAxWidget/index.rst + KiwoomOpenApiWQAxWidgetMixin/index.rst + KiwoomOpenApiWSignalConnector/index.rst + KiwoomOpenApiWSignature/index.rst + + diff --git a/_sources/autoapi/koapy/backend/kiwoom_open_api_w/index.rst b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/index.rst new file mode 100644 index 00000000..952f0a63 --- /dev/null +++ b/_sources/autoapi/koapy/backend/kiwoom_open_api_w/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.backend.kiwoom_open_api_w` +========================================= + +.. py:module:: koapy.backend.kiwoom_open_api_w + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + core/index.rst + + diff --git a/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.rst b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.rst new file mode 100644 index 00000000..7d2dd970 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.rst @@ -0,0 +1,94 @@ +:py:mod:`koapy.backtrader.KiwoomOpenApiPlusBroker` +================================================== + +.. py:module:: koapy.backtrader.KiwoomOpenApiPlusBroker + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusCommInfo + koapy.backtrader.KiwoomOpenApiPlusBroker.MetaKiwoomOpenApiPlusBroker + koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusBroker + + + + +.. py:class:: KiwoomOpenApiPlusCommInfo(*args, **kwargs) + + Bases: :py:obj:`backtrader.comminfo.CommInfoBase` + + .. py:attribute:: params + :annotation: = [['stocklike', True], None, ['percabs', False], ['commission', 0.015], ['tax', 0.25], ['mult', 1.0]] + + + + +.. py:class:: MetaKiwoomOpenApiPlusBroker(cls, name, bases, dct) + + Bases: :py:obj:`backtrader.BrokerBase.__class__` + + +.. py:class:: KiwoomOpenApiPlusBroker(*args, **kwargs) + + Bases: :py:obj:`with_metaclass`\ (\ :py:obj:`MetaKiwoomOpenApiPlusBroker`\ , :py:obj:`BrokerBase`\ ) + + .. py:attribute:: params + :annotation: = [['use_positions', True], None] + + + + .. py:method:: start(self) + + + .. py:method:: data_started(self, data) + + + .. py:method:: stop(self) + + + .. py:method:: getcash(self) + + + .. py:method:: getvalue(self, datas=None) + + + .. py:method:: getposition(self, data, clone=True) + + + .. py:method:: orderstatus(self, order) + + + .. py:method:: buy(self, owner, data, size, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs) + + + .. py:method:: sell(self, owner, data, size, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs) + + + .. py:method:: cancel(self, order) + + + .. py:method:: notify(self, order) + + + .. py:method:: get_notification(self) + + + .. py:method:: next(self) + + + .. py:method:: submit(self, order) + + + .. py:method:: add_order_history(self, orders, notify=False) + + + .. py:method:: set_fund_history(self, fund) + + + diff --git a/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.rst b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.rst new file mode 100644 index 00000000..b572be25 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.rst @@ -0,0 +1,65 @@ +:py:mod:`koapy.backtrader.KiwoomOpenApiPlusData` +================================================ + +.. py:module:: koapy.backtrader.KiwoomOpenApiPlusData + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KiwoomOpenApiPlusData.MetaKiwoomOpenApiPlusData + koapy.backtrader.KiwoomOpenApiPlusData.KiwoomOpenApiPlusData + + + + +.. py:class:: MetaKiwoomOpenApiPlusData(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`DataBase`\ ) + + +.. py:class:: KiwoomOpenApiPlusData(*args, **kwargs) + + Bases: :py:obj:`backtrader.feed.DataBase`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:attribute:: params + :annotation: = [['qcheck', 0.5], ['historical', False], ['backfill_start', True], ['backfill', True],... + + + + .. py:method:: isnaive(self, dt) + + + .. py:method:: asutc(self, dt, tz=None, naive=True) + + + .. py:method:: date2num(self, dt, tz=None) + + + .. py:method:: num2date(self, dt=None, tz=None, naive=False) + + + .. py:method:: fromtimestamp(self, timestamp, tz=None) + + + .. py:method:: islive(self) + + + .. py:method:: setenvironment(self, env) + + + .. py:method:: start(self) + + + .. py:method:: stop(self) + + + .. py:method:: haslivedata(self) + + + diff --git a/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.rst b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.rst new file mode 100644 index 00000000..41aa0621 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.rst @@ -0,0 +1,133 @@ +:py:mod:`koapy.backtrader.KiwoomOpenApiPlusEventStreamer` +========================================================= + +.. py:module:: koapy.backtrader.KiwoomOpenApiPlusEventStreamer + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusPriceEventChannel + koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusOrderEventChannel + koapy.backtrader.KiwoomOpenApiPlusEventStreamer.MetaKiwoomOpenApiPlusEventStreamer + koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusEventStreamer + + + + +.. py:class:: KiwoomOpenApiPlusPriceEventChannel(stub) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: close(self) + + + .. py:method:: initialize(self) + + + .. py:method:: register_code(self, code) + + + .. py:method:: is_for_code(self, response, code) + + + .. py:method:: filter_for_code(self, code) + + + .. py:method:: is_valid_price_event(self, response) + + + .. py:method:: filter_price_event(self) + + + .. py:method:: time_to_timestamp(self, fid20) + + + .. py:method:: event_to_dict(self, response) + + + .. py:method:: convert_to_dict(self) + + + .. py:method:: get_observable_for_code(self, code) + + + +.. py:class:: KiwoomOpenApiPlusOrderEventChannel(stub) + + .. py:method:: close(self) + + + .. py:method:: is_chejan_response(self, response) + + + .. py:method:: filter_chejan_response(self) + + + .. py:method:: event_to_dict(self, response) + + + .. py:method:: convert_to_dict(self) + + + .. py:method:: get_observable(self) + + + +.. py:class:: MetaKiwoomOpenApiPlusEventStreamer(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`Observer`\ ) + + Metaclass for defining Abstract Base Classes (ABCs). + + Use this metaclass to create an ABC. An ABC can be subclassed + directly, and then acts as a mix-in class. You can also register + unrelated concrete classes (even built-in classes) and unrelated + ABCs as 'virtual subclasses' -- these and their descendants will + be considered subclasses of the registering ABC by the built-in + issubclass() function, but the registering ABC won't show up in + their MRO (Method Resolution Order) nor will method + implementations defined by the registering ABC be callable (not + even via super()). + + +.. py:class:: KiwoomOpenApiPlusEventStreamer(stub, queue) + + Bases: :py:obj:`rx.core.typing.Observer`, :py:obj:`koapy.utils.logging.Logging.Logging` + + Observer abstract base class + + An Observer is the entity that receives all emissions of a subscribed + Observable. + + .. py:method:: on_next(self, value) + + Notifies the observer of a new element in the sequence. + + :param value: The received element. + + + .. py:method:: on_error(self, error) + + Notifies the observer that an exception has occurred. + + :param error: The error that has occurred. + + + .. py:method:: on_completed(self) + + Notifies the observer of the end of the sequence. + + + .. py:method:: rates(self, code) + + + .. py:method:: events(self) + + + diff --git a/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.rst b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.rst new file mode 100644 index 00000000..024010b5 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.rst @@ -0,0 +1,180 @@ +:py:mod:`koapy.backtrader.KiwoomOpenApiPlusStore` +================================================= + +.. py:module:: koapy.backtrader.KiwoomOpenApiPlusStore + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KiwoomOpenApiPlusStore.HistoricalPriceRecord + koapy.backtrader.KiwoomOpenApiPlusStore.API + koapy.backtrader.KiwoomOpenApiPlusStore.MetaSingleton + koapy.backtrader.KiwoomOpenApiPlusStore.MetaKiwoomOpenApiPlusStore + koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusStore + + + + +.. py:exception:: KiwoomOpenApiPlusJsonError(code, message=None) + + Bases: :py:obj:`koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusNegativeReturnCodeError` + + Common base class for all non-exit exceptions. + + .. py:method:: error_response(self, description=None) + + + +.. py:exception:: KiwoomOpenApiPlusTimeFrameError + + Bases: :py:obj:`KiwoomOpenApiPlusJsonError` + + Common base class for all non-exit exceptions. + + +.. py:class:: HistoricalPriceRecord + + Bases: :py:obj:`collections.namedtuple`\ (\ :py:obj:`'HistoricalPriceRecord'`\ , [\ :py:obj:`'time'`\ , :py:obj:`'open'`\ , :py:obj:`'high'`\ , :py:obj:`'low'`\ , :py:obj:`'close'`\ , :py:obj:`'volume'`\ ]\ ) + + Built-in immutable sequence. + + If no argument is given, the constructor returns an empty tuple. + If iterable is specified the tuple is initialized from iterable's items. + + If the argument is a tuple, the return value is the same object. + + .. py:method:: from_tuple(cls, tup) + :classmethod: + + + .. py:method:: records_from_dataframe(cls, df) + :classmethod: + + + .. py:method:: dict_records_from_dataframe(cls, df) + :classmethod: + + + +.. py:class:: API(context) + + .. py:method:: get_instruments_original(self, account, instruments) + + + .. py:method:: get_instruments(self, account, instruments) + + + .. py:method:: get_history(self, trcode, inputs, dtbegin=None, dtend=None) + + + .. py:method:: get_positions(self, account) + + + .. py:method:: get_account(self, account) + + + .. py:method:: create_order(self, account, **kwargs) + + + .. py:method:: close_order(self, account, oid, size, dataname) + + + .. py:method:: get_today_quotes_by_code(self, codes=None) + + + +.. py:class:: MetaSingleton(cls, clsname, bases, dct) + + Bases: :py:obj:`backtrader.metabase.MetaParams` + + +.. py:class:: MetaKiwoomOpenApiPlusStore(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`MetaSingleton` + + +.. py:class:: KiwoomOpenApiPlusStore(context=None) + + Bases: :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:attribute:: BrokerCls + + + + + .. py:attribute:: DataCls + + + + + .. py:attribute:: params + :annotation: = [['account', ''], ['account_tmout', 60.0]] + + + + .. py:method:: getdata(cls, *args, **kwargs) + :classmethod: + + + .. py:method:: getbroker(cls, *args, **kwargs) + :classmethod: + + + .. py:method:: start(self, data=None, broker=None) + + + .. py:method:: initial_today_historical_msg(self, data=None) + + + .. py:method:: stop(self) + + + .. py:method:: put_notification(self, msg, *args, **kwargs) + + + .. py:method:: get_notifications(self) + + + .. py:method:: timeoffset(self) + + + .. py:method:: get_granularity(self, timeframe, compression, default=None) + + + .. py:method:: get_instrument(self, dataname) + + + .. py:method:: streaming_events(self, tmout=None) + + + .. py:method:: candles(self, dataname, dtbegin, dtend, timeframe, compression) + + + .. py:method:: streaming_prices(self, dataname, tmout=None) + + + .. py:method:: get_cash(self) + + + .. py:method:: get_value(self) + + + .. py:method:: get_positions(self) + + + .. py:method:: broker_threads(self) + + + .. py:method:: order_create(self, order, stopside=None, takeside=None, **kwargs) + + + .. py:method:: order_cancel(self, order) + + + diff --git a/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.rst b/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.rst new file mode 100644 index 00000000..df3352cd --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.rst @@ -0,0 +1,44 @@ +:py:mod:`koapy.backtrader.KrxHistoricalDailyPriceData` +====================================================== + +.. py:module:: koapy.backtrader.KrxHistoricalDailyPriceData + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KrxHistoricalDailyPriceData.KrxHistoricalDailyPriceData + + + + +.. py:class:: KrxHistoricalDailyPriceData + + Bases: :py:obj:`backtrader.feed.DataBase` + + .. py:attribute:: params + :annotation: = [['loader', None], ['symbol', None], ['name', None], ['fromdate', None], ['todate', None],... + + + + .. py:attribute:: lines + :annotation: = ['amount', 'marketcap', 'shares'] + + + + .. py:method:: start(self) + + + .. py:method:: stop(self) + + + .. py:method:: adddata_fromfile(cls, cerebro, filename, symbols=None, fromdate=None, todate=None, progress_bar=True) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.rst b/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.rst new file mode 100644 index 00000000..7deeb8e7 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.rst @@ -0,0 +1,42 @@ +:py:mod:`koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite` +================================================================ + +.. py:module:: koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite.KrxHistoricalDailyPriceDataFromSQLite + + + + +.. py:class:: KrxHistoricalDailyPriceDataFromSQLite + + Bases: :py:obj:`koapy.backtrader.SQLiteData.SQLiteData` + + .. py:attribute:: params + :annotation: = [['engine', None], ['symbol', None], ['name', None], ['fromdate', None], ['todate', None],... + + + + .. py:attribute:: lines + :annotation: = ['amount', 'marketcap', 'shares'] + + + + .. py:method:: dump_from_store(cls, source_filename, dest_filename, symbols=None, fromdate=None, todate=None, progress_bar=True) + :classmethod: + + + .. py:method:: adddata_fromfile(cls, cerebro, filename, symbols=None, fromdate=None, todate=None, progress_bar=True) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/backtrader/KrxTradingCalendar/index.rst b/_sources/autoapi/koapy/backtrader/KrxTradingCalendar/index.rst new file mode 100644 index 00000000..fce10840 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/KrxTradingCalendar/index.rst @@ -0,0 +1,47 @@ +:py:mod:`koapy.backtrader.KrxTradingCalendar` +============================================= + +.. py:module:: koapy.backtrader.KrxTradingCalendar + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.KrxTradingCalendar.ExchangeCalendarsTradingCalendar + koapy.backtrader.KrxTradingCalendar.KrxTradingCalendar + + + + +.. py:class:: ExchangeCalendarsTradingCalendar + + Bases: :py:obj:`backtrader.tradingcal.TradingCalendarBase` + + .. py:attribute:: params + :annotation: = [['calendar', None], ['cachesize', 365]] + + + + .. py:method:: schedule(self, day, tz=None) + + day: expecting naive datetime.datetime day in utc timezone + tz: treat/localize internal naive datetimes to this timezone + returns: (opening, closing) naive datetime.datetime pair in utc timezone + + + +.. py:class:: KrxTradingCalendar + + Bases: :py:obj:`ExchangeCalendarsTradingCalendar` + + .. py:attribute:: params + :annotation: = [['calendar', 'XKRX'], ['cachesize', 365]] + + + + diff --git a/_sources/autoapi/koapy/backtrader/SQLAlchemyData/index.rst b/_sources/autoapi/koapy/backtrader/SQLAlchemyData/index.rst new file mode 100644 index 00000000..cef5df22 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/SQLAlchemyData/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.backtrader.SQLAlchemyData` +========================================= + +.. py:module:: koapy.backtrader.SQLAlchemyData + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.SQLAlchemyData.SQLAlchemyData + + + + +.. py:class:: SQLAlchemyData + + Bases: :py:obj:`backtrader.feed.DataBase` + + .. py:attribute:: params + :annotation: = [['url', None], ['engine', None], ['connection', None], ['tablename', None], ['timestampcolumn',... + + + + .. py:method:: start(self) + + + .. py:method:: stop(self) + + + diff --git a/_sources/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.rst b/_sources/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.rst new file mode 100644 index 00000000..22f0cc11 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.rst @@ -0,0 +1,29 @@ +:py:mod:`koapy.backtrader.SQLAlchemySQLiteData` +=============================================== + +.. py:module:: koapy.backtrader.SQLAlchemySQLiteData + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.SQLAlchemySQLiteData.SQLAlchemySQLiteData + + + + +.. py:class:: SQLAlchemySQLiteData + + Bases: :py:obj:`koapy.backtrader.SQLAlchemyData.SQLAlchemyData` + + .. py:attribute:: params + :annotation: = [['filename', None]] + + + + diff --git a/_sources/autoapi/koapy/backtrader/SQLiteData/index.rst b/_sources/autoapi/koapy/backtrader/SQLiteData/index.rst new file mode 100644 index 00000000..00eca093 --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/SQLiteData/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.backtrader.SQLiteData` +===================================== + +.. py:module:: koapy.backtrader.SQLiteData + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.backtrader.SQLiteData.SQLiteData + + + + +.. py:class:: SQLiteData + + Bases: :py:obj:`backtrader.feed.DataBase` + + .. py:attribute:: params + :annotation: = [['filename', None], ['connection', None], ['engine', None], ['tablename', None],... + + + + .. py:method:: start(self) + + + .. py:method:: stop(self) + + + diff --git a/_sources/autoapi/koapy/backtrader/index.rst b/_sources/autoapi/koapy/backtrader/index.rst new file mode 100644 index 00000000..78b1b3af --- /dev/null +++ b/_sources/autoapi/koapy/backtrader/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.backtrader` +========================== + +.. py:module:: koapy.backtrader + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KiwoomOpenApiPlusBroker/index.rst + KiwoomOpenApiPlusData/index.rst + KiwoomOpenApiPlusEventStreamer/index.rst + KiwoomOpenApiPlusStore/index.rst + KrxHistoricalDailyPriceData/index.rst + KrxHistoricalDailyPriceDataFromSQLite/index.rst + KrxTradingCalendar/index.rst + SQLAlchemyData/index.rst + SQLAlchemySQLiteData/index.rst + SQLiteData/index.rst + + diff --git a/_sources/autoapi/koapy/cli/__main__/index.rst b/_sources/autoapi/koapy/cli/__main__/index.rst new file mode 100644 index 00000000..9f1a8909 --- /dev/null +++ b/_sources/autoapi/koapy/cli/__main__/index.rst @@ -0,0 +1,8 @@ +:orphan: + +:py:mod:`koapy.cli.__main__` +============================ + +.. py:module:: koapy.cli.__main__ + + diff --git a/_sources/autoapi/koapy/cli/commands/disable/auto_login/index.rst b/_sources/autoapi/koapy/cli/commands/disable/auto_login/index.rst new file mode 100644 index 00000000..9e3864a1 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/disable/auto_login/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.cli.commands.disable.auto_login` +=============================================== + +.. py:module:: koapy.cli.commands.disable.auto_login + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.disable.auto_login.disable_auto_login_after_login + koapy.cli.commands.disable.auto_login.disable_auto_login_without_login + koapy.cli.commands.disable.auto_login.auto_login + + + +.. py:function:: disable_auto_login_after_login(port) + + +.. py:function:: disable_auto_login_without_login() + + +.. py:function:: auto_login(port) + + diff --git a/_sources/autoapi/koapy/cli/commands/disable/index.rst b/_sources/autoapi/koapy/cli/commands/disable/index.rst new file mode 100644 index 00000000..d0482b91 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/disable/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.disable` +==================================== + +.. py:module:: koapy.cli.commands.disable + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + auto_login/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.disable.auto_login + koapy.cli.commands.disable.disable + + + +.. py:function:: auto_login(port) + + +.. py:function:: disable() + + diff --git a/_sources/autoapi/koapy/cli/commands/enable/auto_login/index.rst b/_sources/autoapi/koapy/cli/commands/enable/auto_login/index.rst new file mode 100644 index 00000000..eb198141 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/enable/auto_login/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.enable.auto_login` +============================================== + +.. py:module:: koapy.cli.commands.enable.auto_login + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.enable.auto_login.auto_login + + + +.. py:function:: auto_login(port) + + diff --git a/_sources/autoapi/koapy/cli/commands/enable/index.rst b/_sources/autoapi/koapy/cli/commands/enable/index.rst new file mode 100644 index 00000000..72b685fa --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/enable/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.enable` +=================================== + +.. py:module:: koapy.cli.commands.enable + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + auto_login/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.enable.auto_login + koapy.cli.commands.enable.enable + + + +.. py:function:: auto_login(port) + + +.. py:function:: enable() + + diff --git a/_sources/autoapi/koapy/cli/commands/generate/grpc/index.rst b/_sources/autoapi/koapy/cli/commands/generate/grpc/index.rst new file mode 100644 index 00000000..d854fbe4 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/generate/grpc/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.generate.grpc` +========================================== + +.. py:module:: koapy.cli.commands.generate.grpc + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + ssl_credentials/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.grpc.ssl_credentials + koapy.cli.commands.generate.grpc.grpc + + + +.. py:function:: ssl_credentials() + + +.. py:function:: grpc() + + diff --git a/_sources/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.rst b/_sources/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.rst new file mode 100644 index 00000000..00e578a3 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.cli.commands.generate.grpc.ssl_credentials` +========================================================== + +.. py:module:: koapy.cli.commands.generate.grpc.ssl_credentials + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.grpc.ssl_credentials.generate_self_signed_key_cert + koapy.cli.commands.generate.grpc.ssl_credentials.generate_key_cert_signed_by_authority + koapy.cli.commands.generate.grpc.ssl_credentials.ssl_credentials + + + +.. py:function:: generate_self_signed_key_cert(organization_name, common_name, key_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None) + + +.. py:function:: generate_key_cert_signed_by_authority(organization_name, common_name, alternative_dns_names=None, key_filename=None, csr_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None, authority_key_filename=None, authority_cert_filename=None, authority_key_password=None) + + +.. py:function:: ssl_credentials() + + diff --git a/_sources/autoapi/koapy/cli/commands/generate/index.rst b/_sources/autoapi/koapy/cli/commands/generate/index.rst new file mode 100644 index 00000000..9a4b9539 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/generate/index.rst @@ -0,0 +1,40 @@ +:py:mod:`koapy.cli.commands.generate` +===================================== + +.. py:module:: koapy.cli.commands.generate + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + grpc/index.rst + openapi/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.grpc + koapy.cli.commands.generate.openapi + koapy.cli.commands.generate.generate + + + +.. py:function:: grpc() + + +.. py:function:: openapi() + + +.. py:function:: generate() + + diff --git a/_sources/autoapi/koapy/cli/commands/generate/openapi/index.rst b/_sources/autoapi/koapy/cli/commands/generate/openapi/index.rst new file mode 100644 index 00000000..bdb19d4e --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/generate/openapi/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.generate.openapi` +============================================= + +.. py:module:: koapy.cli.commands.generate.openapi + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + python_stubs/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.openapi.python_stubs + koapy.cli.commands.generate.openapi.openapi + + + +.. py:function:: python_stubs(dispatch_class_name, dispatch_file_path, event_class_name, event_file_path, encoding, force_overwrite) + + +.. py:function:: openapi() + + diff --git a/_sources/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.rst b/_sources/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.rst new file mode 100644 index 00000000..96a85a45 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.rst @@ -0,0 +1,53 @@ +:py:mod:`koapy.cli.commands.generate.openapi.python_stubs` +========================================================== + +.. py:module:: koapy.cli.commands.generate.openapi.python_stubs + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.openapi.python_stubs.python_stubs + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.generate.openapi.python_stubs.default_dispatch_class_name + koapy.cli.commands.generate.openapi.python_stubs.default_dispatch_file_path + koapy.cli.commands.generate.openapi.python_stubs.default_event_class_name + koapy.cli.commands.generate.openapi.python_stubs.default_event_file_path + + +.. py:data:: default_dispatch_class_name + :annotation: = KiwoomOpenApiPlusDispatchFunctionsGenerated + + + +.. py:data:: default_dispatch_file_path + + + + +.. py:data:: default_event_class_name + :annotation: = KiwoomOpenApiPlusEventFunctionsGenerated + + + +.. py:data:: default_event_file_path + + + + +.. py:function:: python_stubs(dispatch_class_name, dispatch_file_path, event_class_name, event_file_path, encoding, force_overwrite) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/account_data/deposit/index.rst b/_sources/autoapi/koapy/cli/commands/get/account_data/deposit/index.rst new file mode 100644 index 00000000..f66c7640 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/account_data/deposit/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.get.account_data.deposit` +===================================================== + +.. py:module:: koapy.cli.commands.get.account_data.deposit + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.deposit.deposit + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.deposit.logger + + +.. py:data:: logger + + + + +.. py:function:: deposit(account, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/account_data/evaluation/index.rst b/_sources/autoapi/koapy/cli/commands/get/account_data/evaluation/index.rst new file mode 100644 index 00000000..3cc66029 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/account_data/evaluation/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.get.account_data.evaluation` +======================================================== + +.. py:module:: koapy.cli.commands.get.account_data.evaluation + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.evaluation.evaluation + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.evaluation.logger + + +.. py:data:: logger + + + + +.. py:function:: evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/account_data/index.rst b/_sources/autoapi/koapy/cli/commands/get/account_data/index.rst new file mode 100644 index 00000000..0ac724f7 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/account_data/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.cli.commands.get.account_data` +============================================= + +.. py:module:: koapy.cli.commands.get.account_data + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + deposit/index.rst + evaluation/index.rst + orders/index.rst + userinfo/index.rst + + diff --git a/_sources/autoapi/koapy/cli/commands/get/account_data/orders/index.rst b/_sources/autoapi/koapy/cli/commands/get/account_data/orders/index.rst new file mode 100644 index 00000000..a034a9d7 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/account_data/orders/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.get.account_data.orders` +==================================================== + +.. py:module:: koapy.cli.commands.get.account_data.orders + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.orders.orders + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.orders.logger + + +.. py:data:: logger + + + + +.. py:function:: orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/account_data/userinfo/index.rst b/_sources/autoapi/koapy/cli/commands/get/account_data/userinfo/index.rst new file mode 100644 index 00000000..e0aa64ab --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/account_data/userinfo/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.account_data.userinfo` +====================================================== + +.. py:module:: koapy.cli.commands.get.account_data.userinfo + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.account_data.userinfo.userinfo + + + +.. py:function:: userinfo(port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/chart_data/daily/index.rst b/_sources/autoapi/koapy/cli/commands/get/chart_data/daily/index.rst new file mode 100644 index 00000000..64104b79 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/chart_data/daily/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.get.chart_data.daily` +================================================= + +.. py:module:: koapy.cli.commands.get.chart_data.daily + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.chart_data.daily.daily + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.chart_data.daily.logger + + +.. py:data:: logger + + + + +.. py:function:: daily(code, output, format, start_date, end_date, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/chart_data/index.rst b/_sources/autoapi/koapy/cli/commands/get/chart_data/index.rst new file mode 100644 index 00000000..df189e8d --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/chart_data/index.rst @@ -0,0 +1,16 @@ +:py:mod:`koapy.cli.commands.get.chart_data` +=========================================== + +.. py:module:: koapy.cli.commands.get.chart_data + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + daily/index.rst + minute/index.rst + + diff --git a/_sources/autoapi/koapy/cli/commands/get/chart_data/minute/index.rst b/_sources/autoapi/koapy/cli/commands/get/chart_data/minute/index.rst new file mode 100644 index 00000000..fa032595 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/chart_data/minute/index.rst @@ -0,0 +1,41 @@ +:py:mod:`koapy.cli.commands.get.chart_data.minute` +================================================== + +.. py:module:: koapy.cli.commands.get.chart_data.minute + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.chart_data.minute.minute + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.chart_data.minute.logger + koapy.cli.commands.get.chart_data.minute.minute_intervals + + +.. py:data:: logger + + + + +.. py:data:: minute_intervals + :annotation: = ['1', '3', '5', '10', '15', '30', '45', '60'] + + + +.. py:function:: minute(code, interval, output, format, start_date, end_date, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/index.rst b/_sources/autoapi/koapy/cli/commands/get/index.rst new file mode 100644 index 00000000..ffdbb7bc --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/index.rst @@ -0,0 +1,116 @@ +:py:mod:`koapy.cli.commands.get` +================================ + +.. py:module:: koapy.cli.commands.get + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + account_data/index.rst + chart_data/index.rst + openapi_meta/index.rst + stock_meta/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.deposit + koapy.cli.commands.get.evaluation + koapy.cli.commands.get.orders + koapy.cli.commands.get.userinfo + koapy.cli.commands.get.daily + koapy.cli.commands.get.minute + koapy.cli.commands.get.errmsg + koapy.cli.commands.get.modulepath + koapy.cli.commands.get.realinfo + koapy.cli.commands.get.trinfo + koapy.cli.commands.get.codelist + koapy.cli.commands.get.stockcode + koapy.cli.commands.get.stockinfo + koapy.cli.commands.get.stockname + koapy.cli.commands.get.get + + + +.. py:function:: deposit(account, port) + + +.. py:function:: evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port) + + +.. py:function:: orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port) + + +.. py:function:: userinfo(port) + + +.. py:function:: daily(code, output, format, start_date, end_date, port) + + +.. py:function:: minute(code, interval, output, format, start_date, end_date, port) + + +.. py:function:: errmsg(err_code) + + +.. py:function:: modulepath() + + +.. py:function:: realinfo(realtypes) + + +.. py:function:: trinfo(trcodes) + + +.. py:function:: codelist(markets, port) + +  + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + + +.. py:function:: stockcode(names, markets, port) + +  + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + + +.. py:function:: stockinfo(code, output, format, port) + + +.. py:function:: stockname(codes, port) + + +.. py:function:: get() + + diff --git a/_sources/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.rst b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.rst new file mode 100644 index 00000000..0d223bee --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.openapi_meta.errmsg` +==================================================== + +.. py:module:: koapy.cli.commands.get.openapi_meta.errmsg + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.openapi_meta.errmsg.errmsg + + + +.. py:function:: errmsg(err_code) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/openapi_meta/index.rst b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/index.rst new file mode 100644 index 00000000..935a5aa5 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.cli.commands.get.openapi_meta` +============================================= + +.. py:module:: koapy.cli.commands.get.openapi_meta + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + errmsg/index.rst + modulepath/index.rst + realinfo/index.rst + trinfo/index.rst + + diff --git a/_sources/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.rst b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.rst new file mode 100644 index 00000000..a73932ce --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.openapi_meta.modulepath` +======================================================== + +.. py:module:: koapy.cli.commands.get.openapi_meta.modulepath + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.openapi_meta.modulepath.modulepath + + + +.. py:function:: modulepath() + + diff --git a/_sources/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.rst b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.rst new file mode 100644 index 00000000..1fb8ef5f --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.openapi_meta.realinfo` +====================================================== + +.. py:module:: koapy.cli.commands.get.openapi_meta.realinfo + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.openapi_meta.realinfo.realinfo + + + +.. py:function:: realinfo(realtypes) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.rst b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.rst new file mode 100644 index 00000000..2a8b2a0b --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.openapi_meta.trinfo` +==================================================== + +.. py:module:: koapy.cli.commands.get.openapi_meta.trinfo + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.openapi_meta.trinfo.trinfo + + + +.. py:function:: trinfo(trcodes) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.rst new file mode 100644 index 00000000..56b8f88d --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.rst @@ -0,0 +1,52 @@ +:py:mod:`koapy.cli.commands.get.stock_meta.codelist` +==================================================== + +.. py:module:: koapy.cli.commands.get.stock_meta.codelist + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.codelist.codelist + koapy.cli.commands.get.stock_meta.codelist.main + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.codelist.market_codes + + +.. py:data:: market_codes + :annotation: = ['0', '10', '3', '8', '50', '4', '5', '6', '9', '30', 'all'] + + + +.. py:function:: codelist(markets, port) + +  + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + + +.. py:function:: main() + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.rst new file mode 100644 index 00000000..6435f103 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.rst @@ -0,0 +1,108 @@ +:py:mod:`koapy.cli.commands.get.stock_meta.codelist_interactive` +================================================================ + +.. py:module:: koapy.cli.commands.get.stock_meta.codelist_interactive + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.codelist_interactive.MarketEntry + koapy.cli.commands.get.stock_meta.codelist_interactive.StockEntry + koapy.cli.commands.get.stock_meta.codelist_interactive.StatusBarHandler + koapy.cli.commands.get.stock_meta.codelist_interactive.Screen + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.codelist_interactive.screen_len + koapy.cli.commands.get.stock_meta.codelist_interactive.wrapper + koapy.cli.commands.get.stock_meta.codelist_interactive.codelist_interactive + koapy.cli.commands.get.stock_meta.codelist_interactive.main + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.codelist_interactive.markets + + +.. py:class:: MarketEntry(code, name) + + .. py:method:: to_string(self) + + + +.. py:class:: StockEntry(code, name) + + .. py:method:: to_string(self) + + + +.. py:data:: markets + + + + +.. py:class:: StatusBarHandler(screen, level=logging.NOTSET) + + Bases: :py:obj:`logging.Handler` + + Handler instances dispatch logging events to specific destinations. + + The base handler class. Acts as a placeholder which defines the Handler + interface. Handlers can optionally use Formatter instances to format + records as desired. By default, no formatter is specified; in this case, + the 'raw' message as determined by record.message is logged. + + .. py:method:: emit(self, record) + + Do whatever it takes to actually log the specified logging record. + + This version is intended to be implemented by subclasses and so + raises a NotImplementedError. + + + +.. py:function:: screen_len(str) + + +.. py:class:: Screen(screen) + + .. py:method:: refresh_header_bar(self) + + + .. py:method:: set_header_bar(self, text) + + + .. py:method:: refresh_footer_bar(self) + + + .. py:method:: set_footer_bar(self, text) + + + .. py:method:: show_entries(self, entries) + + + +.. py:function:: wrapper(stdscr) + + +.. py:function:: codelist_interactive() + + +.. py:function:: main() + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/index.rst new file mode 100644 index 00000000..af73770a --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/index.rst @@ -0,0 +1,19 @@ +:py:mod:`koapy.cli.commands.get.stock_meta` +=========================================== + +.. py:module:: koapy.cli.commands.get.stock_meta + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + codelist/index.rst + codelist_interactive/index.rst + stockcode/index.rst + stockinfo/index.rst + stockname/index.rst + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.rst new file mode 100644 index 00000000..181686d2 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.rst @@ -0,0 +1,48 @@ +:py:mod:`koapy.cli.commands.get.stock_meta.stockcode` +===================================================== + +.. py:module:: koapy.cli.commands.get.stock_meta.stockcode + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.stockcode.stockcode + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.stockcode.market_codes + + +.. py:data:: market_codes + :annotation: = ['0', '10', '3', '8', '50', '4', '5', '6', '9', '30', 'all'] + + + +.. py:function:: stockcode(names, markets, port) + +  + Possible market codes are: + 0 : 장내 + 10 : 코스닥 + 3 : ELW + 8 : ETF + 50 : KONEX + 4 : 뮤추얼펀드 + 5 : 신주인수권 + 6 : 리츠 + 9 : 하이얼펀드 + 30 : K-OTC + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.rst new file mode 100644 index 00000000..c41f9e7b --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.stock_meta.stockinfo` +===================================================== + +.. py:module:: koapy.cli.commands.get.stock_meta.stockinfo + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.stockinfo.stockinfo + + + +.. py:function:: stockinfo(code, output, format, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.rst b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.rst new file mode 100644 index 00000000..9e8a8e81 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.get.stock_meta.stockname` +===================================================== + +.. py:module:: koapy.cli.commands.get.stock_meta.stockname + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.get.stock_meta.stockname.stockname + + + +.. py:function:: stockname(codes, port) + + diff --git a/_sources/autoapi/koapy/cli/commands/index.rst b/_sources/autoapi/koapy/cli/commands/index.rst new file mode 100644 index 00000000..88dc1e16 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/index.rst @@ -0,0 +1,23 @@ +:py:mod:`koapy.cli.commands` +============================ + +.. py:module:: koapy.cli.commands + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + disable/index.rst + enable/index.rst + generate/index.rst + get/index.rst + install/index.rst + serve/index.rst + show/index.rst + uninstall/index.rst + update/index.rst + + diff --git a/_sources/autoapi/koapy/cli/commands/install/index.rst b/_sources/autoapi/koapy/cli/commands/install/index.rst new file mode 100644 index 00000000..b349bdc0 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/install/index.rst @@ -0,0 +1,40 @@ +:py:mod:`koapy.cli.commands.install` +==================================== + +.. py:module:: koapy.cli.commands.install + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + openapi/index.rst + pywin32/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.install.openapi + koapy.cli.commands.install.pywin32 + koapy.cli.commands.install.install + + + +.. py:function:: openapi(target, cleanup) + + +.. py:function:: pywin32(version) + + +.. py:function:: install() + + diff --git a/_sources/autoapi/koapy/cli/commands/install/openapi/index.rst b/_sources/autoapi/koapy/cli/commands/install/openapi/index.rst new file mode 100644 index 00000000..4003eddc --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/install/openapi/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.install.openapi` +============================================ + +.. py:module:: koapy.cli.commands.install.openapi + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.install.openapi.openapi + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.install.openapi.logger + + +.. py:data:: logger + + + + +.. py:function:: openapi(target, cleanup) + + diff --git a/_sources/autoapi/koapy/cli/commands/install/pywin32/index.rst b/_sources/autoapi/koapy/cli/commands/install/pywin32/index.rst new file mode 100644 index 00000000..ac69a232 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/install/pywin32/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.install.pywin32` +============================================ + +.. py:module:: koapy.cli.commands.install.pywin32 + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.install.pywin32.pywin32 + + + +.. py:function:: pywin32(version) + + diff --git a/_sources/autoapi/koapy/cli/commands/serve/index.rst b/_sources/autoapi/koapy/cli/commands/serve/index.rst new file mode 100644 index 00000000..2fe47ba9 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/serve/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.cli.commands.serve` +================================== + +.. py:module:: koapy.cli.commands.serve + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.serve.grpc_server_and_client_options + koapy.cli.commands.serve.full_verbose_option + koapy.cli.commands.serve.serve + + + +.. py:function:: grpc_server_and_client_options() + + +.. py:function:: full_verbose_option(*args, **kwargs) + + +.. py:function:: serve(ctx, verbose, **kwargs) + + diff --git a/_sources/autoapi/koapy/cli/commands/show/account_window/index.rst b/_sources/autoapi/koapy/cli/commands/show/account_window/index.rst new file mode 100644 index 00000000..161cba89 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/show/account_window/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.show.account_window` +================================================ + +.. py:module:: koapy.cli.commands.show.account_window + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.show.account_window.account_window + + + +.. py:function:: account_window(port) + + diff --git a/_sources/autoapi/koapy/cli/commands/show/index.rst b/_sources/autoapi/koapy/cli/commands/show/index.rst new file mode 100644 index 00000000..b541e8a9 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/show/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.show` +================================= + +.. py:module:: koapy.cli.commands.show + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + account_window/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.show.account_window + koapy.cli.commands.show.show + + + +.. py:function:: account_window(port) + + +.. py:function:: show() + + diff --git a/_sources/autoapi/koapy/cli/commands/uninstall/index.rst b/_sources/autoapi/koapy/cli/commands/uninstall/index.rst new file mode 100644 index 00000000..360de8a0 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/uninstall/index.rst @@ -0,0 +1,40 @@ +:py:mod:`koapy.cli.commands.uninstall` +====================================== + +.. py:module:: koapy.cli.commands.uninstall + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + openapi/index.rst + pywin32/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.uninstall.openapi + koapy.cli.commands.uninstall.pywin32 + koapy.cli.commands.uninstall.uninstall + + + +.. py:function:: openapi(reboot, cleanup) + + +.. py:function:: pywin32() + + +.. py:function:: uninstall() + + diff --git a/_sources/autoapi/koapy/cli/commands/uninstall/openapi/index.rst b/_sources/autoapi/koapy/cli/commands/uninstall/openapi/index.rst new file mode 100644 index 00000000..0d3cb4d7 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/uninstall/openapi/index.rst @@ -0,0 +1,35 @@ +:py:mod:`koapy.cli.commands.uninstall.openapi` +============================================== + +.. py:module:: koapy.cli.commands.uninstall.openapi + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.uninstall.openapi.openapi + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.uninstall.openapi.logger + + +.. py:data:: logger + + + + +.. py:function:: openapi(reboot, cleanup) + + diff --git a/_sources/autoapi/koapy/cli/commands/uninstall/pywin32/index.rst b/_sources/autoapi/koapy/cli/commands/uninstall/pywin32/index.rst new file mode 100644 index 00000000..b283e34b --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/uninstall/pywin32/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.commands.uninstall.pywin32` +============================================== + +.. py:module:: koapy.cli.commands.uninstall.pywin32 + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.uninstall.pywin32.pywin32 + + + +.. py:function:: pywin32() + + diff --git a/_sources/autoapi/koapy/cli/commands/update/index.rst b/_sources/autoapi/koapy/cli/commands/update/index.rst new file mode 100644 index 00000000..0f0efa22 --- /dev/null +++ b/_sources/autoapi/koapy/cli/commands/update/index.rst @@ -0,0 +1,46 @@ +:py:mod:`koapy.cli.commands.update` +=================================== + +.. py:module:: koapy.cli.commands.update + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.commands.update.get_credentials + koapy.cli.commands.update.verbose_option + koapy.cli.commands.update.update + koapy.cli.commands.update.trinfo + koapy.cli.commands.update.realtype + koapy.cli.commands.update.openapi + koapy.cli.commands.update.proto + + + +.. py:function:: get_credentials(interactive=False) + + +.. py:function:: verbose_option(*args, **kwargs) + + +.. py:function:: update() + + +.. py:function:: trinfo() + + +.. py:function:: realtype() + + +.. py:function:: openapi(interactive) + + +.. py:function:: proto() + + diff --git a/_sources/autoapi/koapy/cli/extensions/functools/index.rst b/_sources/autoapi/koapy/cli/extensions/functools/index.rst new file mode 100644 index 00000000..19e80217 --- /dev/null +++ b/_sources/autoapi/koapy/cli/extensions/functools/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.cli.extensions.functools` +======================================== + +.. py:module:: koapy.cli.extensions.functools + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.extensions.functools.update_wrapper_with_click_params + + + +.. py:function:: update_wrapper_with_click_params(wrapper, wrapped, *args, **kwargs) + + diff --git a/_sources/autoapi/koapy/cli/extensions/index.rst b/_sources/autoapi/koapy/cli/extensions/index.rst new file mode 100644 index 00000000..702e5340 --- /dev/null +++ b/_sources/autoapi/koapy/cli/extensions/index.rst @@ -0,0 +1,17 @@ +:py:mod:`koapy.cli.extensions` +============================== + +.. py:module:: koapy.cli.extensions + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + functools/index.rst + parser/index.rst + verbose_option/index.rst + + diff --git a/_sources/autoapi/koapy/cli/extensions/parser/index.rst b/_sources/autoapi/koapy/cli/extensions/parser/index.rst new file mode 100644 index 00000000..a134d46d --- /dev/null +++ b/_sources/autoapi/koapy/cli/extensions/parser/index.rst @@ -0,0 +1,73 @@ +:py:mod:`koapy.cli.extensions.parser` +===================================== + +.. py:module:: koapy.cli.extensions.parser + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.cli.extensions.parser.ArgumentParser + koapy.cli.extensions.parser.ClickArgumentParser + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.extensions.parser.Function + koapy.cli.extensions.parser.FunctionOrCommand + koapy.cli.extensions.parser.ArgumentDecorator + koapy.cli.extensions.parser.CommandDecorator + + +.. py:data:: Function + + + + +.. py:data:: FunctionOrCommand + + + + +.. py:data:: ArgumentDecorator + + + + +.. py:data:: CommandDecorator + + + + +.. py:class:: ArgumentParser + + .. py:method:: parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace + :abstractmethod: + + + .. py:method:: parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> Tuple[argparse.Namespace, List[str]] + :abstractmethod: + + + +.. py:class:: ClickArgumentParser(params: Sequence[ArgumentDecorator], command: Optional[CommandDecorator] = None, help_option_names: Optional[Sequence[str]] = None) + + Bases: :py:obj:`ArgumentParser` + + .. py:method:: parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> argparse.Namespace + + + .. py:method:: parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) -> Tuple[argparse.Namespace, List[str]] + + + diff --git a/_sources/autoapi/koapy/cli/extensions/verbose_option/index.rst b/_sources/autoapi/koapy/cli/extensions/verbose_option/index.rst new file mode 100644 index 00000000..dc2ff67f --- /dev/null +++ b/_sources/autoapi/koapy/cli/extensions/verbose_option/index.rst @@ -0,0 +1,104 @@ +:py:mod:`koapy.cli.extensions.verbose_option` +============================================= + +.. py:module:: koapy.cli.extensions.verbose_option + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.cli.extensions.verbose_option.VerboseOption + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.extensions.verbose_option.verbose_flag_option + koapy.cli.extensions.verbose_option.no_verbose_flag_option + koapy.cli.extensions.verbose_option.verbose_option + + + +.. py:class:: VerboseOption(*decls, **attrs) + + Bases: :py:obj:`click.Option` + + Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page. Normally, environment variables are not + shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + + .. versionchanged:: 8.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + + .. py:method:: add_to_parser(self, parser, ctx) + + + +.. py:function:: verbose_flag_option(default=0, flag_value=1, show_default=False, metavar='[0...5]', help='Set verbosity level.') + + +.. py:function:: no_verbose_flag_option(help='Force zero verbosity.') + + +.. py:function:: verbose_option(dest='verbose', default=0, flag_value=1, callback=None, expose_value=False, show_default=False) + + diff --git a/_sources/autoapi/koapy/cli/index.rst b/_sources/autoapi/koapy/cli/index.rst new file mode 100644 index 00000000..b50aef94 --- /dev/null +++ b/_sources/autoapi/koapy/cli/index.rst @@ -0,0 +1,176 @@ +:py:mod:`koapy.cli` +=================== + +.. py:module:: koapy.cli + +.. autoapi-nested-parse:: + + Console script for koapy. + + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + commands/index.rst + extensions/index.rst + utils/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.disable + koapy.cli.enable + koapy.cli.generate + koapy.cli.get + koapy.cli.install + koapy.cli.serve + koapy.cli.show + koapy.cli.uninstall + koapy.cli.update + koapy.cli.get_credentials + koapy.cli.fail_with_usage + koapy.cli.verbose_option + koapy.cli.get_logger + koapy.cli.cli + koapy.cli.login + koapy.cli.watch + koapy.cli.order + koapy.cli.main + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.default_encoding + koapy.cli.logger + koapy.cli.help_option_names + koapy.cli.context_settings + koapy.cli.order_types + koapy.cli.quote_types + + +.. py:function:: disable() + + +.. py:function:: enable() + + +.. py:function:: generate() + + +.. py:function:: get() + + +.. py:function:: install() + + +.. py:function:: serve(ctx, verbose, **kwargs) + + +.. py:function:: show() + + +.. py:function:: uninstall() + + +.. py:function:: update() + + +.. py:function:: get_credentials(interactive=False) + + +.. py:function:: fail_with_usage(message=None, ctx=None) + + +.. py:function:: verbose_option(*args, **kwargs) + + +.. py:data:: default_encoding + :annotation: = utf-8 + + + +.. py:function:: get_logger(name=None) + + +.. py:data:: logger + + + + +.. py:data:: help_option_names + :annotation: = ['-h', '--help'] + + + +.. py:data:: context_settings + + + + +.. py:function:: cli() + + +.. py:function:: login(interactive, disable_auto_login, port) + + +.. py:function:: watch(codes, input, fids, realtype, output, format, port) + + +.. py:data:: order_types + :annotation: = ['1', '2', '3', '4', '5', '6'] + + + +.. py:data:: quote_types + :annotation: = ['00', '03', '05', '06', '07', '10', '13', '16', '20', '23', '26', '61', '62', '81'] + + + +.. py:function:: order(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no, format, port) + +  + [주문유형] + 1 : 신규매수 + 2 : 신규매도 + 3 : 매수취소 + 4 : 매도취소 + 5 : 매수정정 + 6 : 매도정정 + +  + [거래구분] + 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. + 00 : 지정가 + 03 : 시장가 + 05 : 조건부지정가 + 06 : 최유리지정가 + 07 : 최우선지정가 + 10 : 지정가IOC + 13 : 시장가IOC + 16 : 최유리IOC + 20 : 지정가FOK + 23 : 시장가FOK + 26 : 최유리FOK + 61 : 장전시간외종가 + 62 : 시간외단일가매매 + 81 : 장후시간외종가 + + +.. py:function:: main() + + diff --git a/_sources/autoapi/koapy/cli/utils/credentials/index.rst b/_sources/autoapi/koapy/cli/utils/credentials/index.rst new file mode 100644 index 00000000..41f7db93 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/credentials/index.rst @@ -0,0 +1,26 @@ +:py:mod:`koapy.cli.utils.credentials` +===================================== + +.. py:module:: koapy.cli.utils.credentials + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.credentials.prompt_credentials + koapy.cli.utils.credentials.get_credentials + + + +.. py:function:: prompt_credentials() + + +.. py:function:: get_credentials(interactive=False) + + diff --git a/_sources/autoapi/koapy/cli/utils/fail_with_usage/index.rst b/_sources/autoapi/koapy/cli/utils/fail_with_usage/index.rst new file mode 100644 index 00000000..a4d799a9 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/fail_with_usage/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.cli.utils.fail_with_usage` +========================================= + +.. py:module:: koapy.cli.utils.fail_with_usage + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.fail_with_usage.get_help + koapy.cli.utils.fail_with_usage.get_help_without_usage + koapy.cli.utils.fail_with_usage.fail_with_usage + + + +.. py:function:: get_help(ctx) + + +.. py:function:: get_help_without_usage(ctx) + + +.. py:function:: fail_with_usage(message=None, ctx=None) + + diff --git a/_sources/autoapi/koapy/cli/utils/grpc_options/index.rst b/_sources/autoapi/koapy/cli/utils/grpc_options/index.rst new file mode 100644 index 00000000..5c4eb1a8 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/grpc_options/index.rst @@ -0,0 +1,271 @@ +:py:mod:`koapy.cli.utils.grpc_options` +====================================== + +.. py:module:: koapy.cli.utils.grpc_options + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.grpc_options.grpc_server_options + koapy.cli.utils.grpc_options.grpc_client_options + koapy.cli.utils.grpc_options.grpc_server_and_client_options + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.grpc_options.grpc_config + koapy.cli.utils.grpc_options.default_server_bind_address + koapy.cli.utils.grpc_options.default_server_host + koapy.cli.utils.grpc_options.default_server_port + koapy.cli.utils.grpc_options.default_client_host + koapy.cli.utils.grpc_options.default_client_port + koapy.cli.utils.grpc_options.default_common_host + koapy.cli.utils.grpc_options.default_common_port + koapy.cli.utils.grpc_options.server_bind_address_option + koapy.cli.utils.grpc_options.server_port_option + koapy.cli.utils.grpc_options.server_key_file_option + koapy.cli.utils.grpc_options.server_cert_file_option + koapy.cli.utils.grpc_options.server_root_certs_file_option + koapy.cli.utils.grpc_options.server_require_client_auth_option + koapy.cli.utils.grpc_options.server_no_require_client_auth_option + koapy.cli.utils.grpc_options.server_options + koapy.cli.utils.grpc_options.client_host_option + koapy.cli.utils.grpc_options.client_port_option + koapy.cli.utils.grpc_options.client_enable_ssl_option + koapy.cli.utils.grpc_options.client_root_certs_file_option + koapy.cli.utils.grpc_options.client_key_file_option + koapy.cli.utils.grpc_options.client_cert_file_option + koapy.cli.utils.grpc_options.client_options + koapy.cli.utils.grpc_options.server_and_client_bind_address_option + koapy.cli.utils.grpc_options.server_and_client_host_option + koapy.cli.utils.grpc_options.server_and_client_port_option + koapy.cli.utils.grpc_options.server_and_client_enable_ssl_option + koapy.cli.utils.grpc_options.server_and_client_server_key_file_option + koapy.cli.utils.grpc_options.server_and_client_server_cert_file_option + koapy.cli.utils.grpc_options.server_and_client_server_root_certs_file_option + koapy.cli.utils.grpc_options.server_and_client_require_client_auth_option + koapy.cli.utils.grpc_options.server_and_client_no_require_client_auth_option + koapy.cli.utils.grpc_options.server_and_client_client_root_certs_file_option + koapy.cli.utils.grpc_options.server_and_client_client_key_file_option + koapy.cli.utils.grpc_options.server_and_client_client_cert_file_option + koapy.cli.utils.grpc_options.server_and_client_options + koapy.cli.utils.grpc_options.server_argument_parser + koapy.cli.utils.grpc_options.client_argument_parser + koapy.cli.utils.grpc_options.server_and_client_argument_parser + + +.. py:data:: grpc_config + + + + +.. py:data:: default_server_bind_address + + + + +.. py:data:: default_server_host + + + + +.. py:data:: default_server_port + + + + +.. py:data:: default_client_host + + + + +.. py:data:: default_client_port + + + + +.. py:data:: default_common_host + + + + +.. py:data:: default_common_port + + + + +.. py:data:: server_bind_address_option + + + + +.. py:data:: server_port_option + + + + +.. py:data:: server_key_file_option + + + + +.. py:data:: server_cert_file_option + + + + +.. py:data:: server_root_certs_file_option + + + + +.. py:data:: server_require_client_auth_option + + + + +.. py:data:: server_no_require_client_auth_option + + + + +.. py:data:: server_options + + + + +.. py:data:: client_host_option + + + + +.. py:data:: client_port_option + + + + +.. py:data:: client_enable_ssl_option + + + + +.. py:data:: client_root_certs_file_option + + + + +.. py:data:: client_key_file_option + + + + +.. py:data:: client_cert_file_option + + + + +.. py:data:: client_options + + + + +.. py:data:: server_and_client_bind_address_option + + + + +.. py:data:: server_and_client_host_option + + + + +.. py:data:: server_and_client_port_option + + + + +.. py:data:: server_and_client_enable_ssl_option + + + + +.. py:data:: server_and_client_server_key_file_option + + + + +.. py:data:: server_and_client_server_cert_file_option + + + + +.. py:data:: server_and_client_server_root_certs_file_option + + + + +.. py:data:: server_and_client_require_client_auth_option + + + + +.. py:data:: server_and_client_no_require_client_auth_option + + + + +.. py:data:: server_and_client_client_root_certs_file_option + + + + +.. py:data:: server_and_client_client_key_file_option + + + + +.. py:data:: server_and_client_client_cert_file_option + + + + +.. py:data:: server_and_client_options + + + + +.. py:function:: grpc_server_options() + + +.. py:function:: grpc_client_options() + + +.. py:function:: grpc_server_and_client_options() + + +.. py:data:: server_argument_parser + + + + +.. py:data:: client_argument_parser + + + + +.. py:data:: server_and_client_argument_parser + + + + diff --git a/_sources/autoapi/koapy/cli/utils/index.rst b/_sources/autoapi/koapy/cli/utils/index.rst new file mode 100644 index 00000000..0a84114d --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/index.rst @@ -0,0 +1,20 @@ +:py:mod:`koapy.cli.utils` +========================= + +.. py:module:: koapy.cli.utils + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + credentials/index.rst + fail_with_usage/index.rst + grpc_options/index.rst + openapi/index.rst + pywin32/index.rst + verbose_option/index.rst + + diff --git a/_sources/autoapi/koapy/cli/utils/openapi/index.rst b/_sources/autoapi/koapy/cli/utils/openapi/index.rst new file mode 100644 index 00000000..671ddd01 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/openapi/index.rst @@ -0,0 +1,53 @@ +:py:mod:`koapy.cli.utils.openapi` +================================= + +.. py:module:: koapy.cli.utils.openapi + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.openapi.download_openapi_installer + koapy.cli.utils.openapi.prepare_issfile_for_install + koapy.cli.utils.openapi.prepare_issfile_for_uninstall + koapy.cli.utils.openapi.run_installer_with_issfile + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.openapi.logger + koapy.cli.utils.openapi.iss_file_encoding + + +.. py:data:: logger + + + + +.. py:data:: iss_file_encoding + :annotation: = euc-kr + + + +.. py:function:: download_openapi_installer(filepath) + + +.. py:function:: prepare_issfile_for_install(filepath, target=None) + + +.. py:function:: prepare_issfile_for_uninstall(filepath, reboot=False) + + +.. py:function:: run_installer_with_issfile(installer, issfile, logfile=None, cwd=None) + + diff --git a/_sources/autoapi/koapy/cli/utils/pywin32/index.rst b/_sources/autoapi/koapy/cli/utils/pywin32/index.rst new file mode 100644 index 00000000..3617fb56 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/pywin32/index.rst @@ -0,0 +1,43 @@ +:py:mod:`koapy.cli.utils.pywin32` +================================= + +.. py:module:: koapy.cli.utils.pywin32 + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.pywin32.get_pywin32_postinstall_script + koapy.cli.utils.pywin32.install_pywin32 + koapy.cli.utils.pywin32.uninstall_pywin32 + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.pywin32.logger + + +.. py:data:: logger + + + + +.. py:function:: get_pywin32_postinstall_script(filepath) + + +.. py:function:: install_pywin32(version=None) + + +.. py:function:: uninstall_pywin32() + + diff --git a/_sources/autoapi/koapy/cli/utils/verbose_option/index.rst b/_sources/autoapi/koapy/cli/utils/verbose_option/index.rst new file mode 100644 index 00000000..bd2f0763 --- /dev/null +++ b/_sources/autoapi/koapy/cli/utils/verbose_option/index.rst @@ -0,0 +1,43 @@ +:py:mod:`koapy.cli.utils.verbose_option` +======================================== + +.. py:module:: koapy.cli.utils.verbose_option + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.verbose_option.verbose_option_callback + koapy.cli.utils.verbose_option.verbose_option + koapy.cli.utils.verbose_option.full_verbose_option + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.cli.utils.verbose_option.full_verbosity + + +.. py:data:: full_verbosity + :annotation: = 5 + + + +.. py:function:: verbose_option_callback(ctx, param, value) + + +.. py:function:: verbose_option(*args, **kwargs) + + +.. py:function:: full_verbose_option(*args, **kwargs) + + diff --git a/_sources/autoapi/koapy/compat/index.rst b/_sources/autoapi/koapy/compat/index.rst new file mode 100644 index 00000000..4039994a --- /dev/null +++ b/_sources/autoapi/koapy/compat/index.rst @@ -0,0 +1,16 @@ +:py:mod:`koapy.compat` +====================== + +.. py:module:: koapy.compat + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + pyside2/index.rst + pywinauto/index.rst + + diff --git a/_sources/autoapi/koapy/compat/pyside2/QtAxContainer/index.rst b/_sources/autoapi/koapy/compat/pyside2/QtAxContainer/index.rst new file mode 100644 index 00000000..fa706a84 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/QtAxContainer/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pyside2.QtAxContainer` +============================================ + +.. py:module:: koapy.compat.pyside2.QtAxContainer + + diff --git a/_sources/autoapi/koapy/compat/pyside2/QtCore/index.rst b/_sources/autoapi/koapy/compat/pyside2/QtCore/index.rst new file mode 100644 index 00000000..1103370c --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/QtCore/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pyside2.QtCore` +===================================== + +.. py:module:: koapy.compat.pyside2.QtCore + + diff --git a/_sources/autoapi/koapy/compat/pyside2/QtGui/index.rst b/_sources/autoapi/koapy/compat/pyside2/QtGui/index.rst new file mode 100644 index 00000000..d5421cec --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/QtGui/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pyside2.QtGui` +==================================== + +.. py:module:: koapy.compat.pyside2.QtGui + + diff --git a/_sources/autoapi/koapy/compat/pyside2/QtNetwork/index.rst b/_sources/autoapi/koapy/compat/pyside2/QtNetwork/index.rst new file mode 100644 index 00000000..eee25144 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/QtNetwork/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pyside2.QtNetwork` +======================================== + +.. py:module:: koapy.compat.pyside2.QtNetwork + + diff --git a/_sources/autoapi/koapy/compat/pyside2/QtWidgets/index.rst b/_sources/autoapi/koapy/compat/pyside2/QtWidgets/index.rst new file mode 100644 index 00000000..0a855fa3 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/QtWidgets/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pyside2.QtWidgets` +======================================== + +.. py:module:: koapy.compat.pyside2.QtWidgets + + diff --git a/_sources/autoapi/koapy/compat/pyside2/index.rst b/_sources/autoapi/koapy/compat/pyside2/index.rst new file mode 100644 index 00000000..87723d57 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pyside2/index.rst @@ -0,0 +1,66 @@ +:py:mod:`koapy.compat.pyside2` +============================== + +.. py:module:: koapy.compat.pyside2 + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + QtAxContainer/index.rst + QtCore/index.rst + QtGui/index.rst + QtNetwork/index.rst + QtWidgets/index.rst + + +Package Contents +---------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.compat.pyside2.get_logger + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.compat.pyside2.config + koapy.compat.pyside2.debug + koapy.compat.pyside2.logger + koapy.compat.pyside2.QT_QPA_PLATFORM_PLUGIN_PATH + + +.. py:data:: config + + + + +.. py:data:: debug + :annotation: = False + + + +.. py:function:: get_logger(name=None) + + +.. py:data:: logger + + + + +.. py:data:: QT_QPA_PLATFORM_PLUGIN_PATH + + + + diff --git a/_sources/autoapi/koapy/compat/pywinauto/findwindows/index.rst b/_sources/autoapi/koapy/compat/pywinauto/findwindows/index.rst new file mode 100644 index 00000000..22f7597f --- /dev/null +++ b/_sources/autoapi/koapy/compat/pywinauto/findwindows/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pywinauto.findwindows` +============================================ + +.. py:module:: koapy.compat.pywinauto.findwindows + + diff --git a/_sources/autoapi/koapy/compat/pywinauto/importlib/index.rst b/_sources/autoapi/koapy/compat/pywinauto/importlib/index.rst new file mode 100644 index 00000000..caab5904 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pywinauto/importlib/index.rst @@ -0,0 +1,63 @@ +:py:mod:`koapy.compat.pywinauto.importlib` +========================================== + +.. py:module:: koapy.compat.pywinauto.importlib + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.compat.pywinauto.importlib.PyWinAutoFinder + koapy.compat.pywinauto.importlib.PyWinAutoLoader + + + + +.. py:class:: PyWinAutoFinder + + Bases: :py:obj:`importlib.abc.MetaPathFinder` + + Abstract base class for import finders on sys.meta_path. + + .. py:method:: find_spec(self, fullname, path, target=None) + + + .. py:method:: register(cls) + :classmethod: + + + .. py:method:: unregister(cls) + :classmethod: + + + +.. py:class:: PyWinAutoLoader + + Bases: :py:obj:`importlib.abc.Loader` + + Abstract base class for import loaders. + + .. py:method:: set_sys_coinit_flags(self) + + + .. py:method:: reset_sys_coinit_flags(self) + + + .. py:method:: create_module(self, spec) + + Return a module to initialize and into which to load. + + This method should raise ImportError if anything prevents it + from creating a new module. It may return None to indicate + that the spec should create the new module. + + + .. py:method:: exec_module(self, module) + + + diff --git a/_sources/autoapi/koapy/compat/pywinauto/index.rst b/_sources/autoapi/koapy/compat/pywinauto/index.rst new file mode 100644 index 00000000..4e4bdf66 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pywinauto/index.rst @@ -0,0 +1,48 @@ +:py:mod:`koapy.compat.pywinauto` +================================ + +.. py:module:: koapy.compat.pywinauto + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + findwindows/index.rst + importlib/index.rst + timings/index.rst + + +Package Contents +---------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.compat.pywinauto.PyWinAutoFinder + + + + +.. py:class:: PyWinAutoFinder + + Bases: :py:obj:`importlib.abc.MetaPathFinder` + + Abstract base class for import finders on sys.meta_path. + + .. py:method:: find_spec(self, fullname, path, target=None) + + + .. py:method:: register(cls) + :classmethod: + + + .. py:method:: unregister(cls) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/compat/pywinauto/timings/index.rst b/_sources/autoapi/koapy/compat/pywinauto/timings/index.rst new file mode 100644 index 00000000..6aa9aa25 --- /dev/null +++ b/_sources/autoapi/koapy/compat/pywinauto/timings/index.rst @@ -0,0 +1,6 @@ +:py:mod:`koapy.compat.pywinauto.timings` +======================================== + +.. py:module:: koapy.compat.pywinauto.timings + + diff --git a/_sources/autoapi/koapy/config/index.rst b/_sources/autoapi/koapy/config/index.rst new file mode 100644 index 00000000..4862a303 --- /dev/null +++ b/_sources/autoapi/koapy/config/index.rst @@ -0,0 +1,183 @@ +:py:mod:`koapy.config` +====================== + +.. py:module:: koapy.config + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.config.read_config + koapy.config.config_from_dict + koapy.config.find_user_config_file_in + koapy.config.find_user_config_file_from + koapy.config.set_user_config + koapy.config.initialize_config_from_given_path + koapy.config.initialize_config_from_expected_paths + koapy.config.get_config + koapy.config.get_user_config + koapy.config.dump_config + koapy.config.save_config + koapy.config.save_user_config + koapy.config.get_executable_from_conda_envname + koapy.config.get_executable_from_conda_envpath + koapy.config.get_executable_from_executable_config + koapy.config.get_32bit_executable + koapy.config.get_64bit_executable + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.config.Config + koapy.config.default_config_filename + koapy.config.default_config_file_directory + koapy.config.default_config_filepath + koapy.config.current_working_directory + koapy.config.home_directory + koapy.config.default_user_config_filename + koapy.config.user_config_filename_cadidates + koapy.config.default_user_config_filepath + koapy.config.default_encoding + koapy.config.default_config + koapy.config.empty_config + koapy.config.user_config + koapy.config.config + koapy.config.debug + + +.. py:data:: Config + + + + +.. py:data:: default_config_filename + :annotation: = config.conf + + + +.. py:data:: default_config_file_directory + + + + +.. py:data:: default_config_filepath + + + + +.. py:data:: current_working_directory + + + + +.. py:data:: home_directory + + + + +.. py:data:: default_user_config_filename + :annotation: = koapy.conf + + + +.. py:data:: user_config_filename_cadidates + + + + +.. py:data:: default_user_config_filepath + + + + +.. py:data:: default_encoding + :annotation: = utf-8 + + + +.. py:function:: read_config(filename: Optional[Union[os.PathLike, str]] = None, encoding: Optional[str] = None) -> Config + + +.. py:function:: config_from_dict(dictionary: Mapping[str, Any]) -> Config + + +.. py:data:: default_config + + + + +.. py:function:: find_user_config_file_in(searching_directory: Optional[Union[os.PathLike, str]] = None) -> Optional[pathlib.Path] + + +.. py:function:: find_user_config_file_from(starting_directory: Optional[Union[os.PathLike, str]] = None) -> Optional[pathlib.Path] + + +.. py:data:: empty_config + + + + +.. py:data:: user_config + + + + +.. py:data:: config + + + + +.. py:function:: set_user_config(c: Config) -> Config + + +.. py:function:: initialize_config_from_given_path(filename: Optional[Union[os.PathLike, str]] = None) -> bool + + +.. py:function:: initialize_config_from_expected_paths() -> bool + + +.. py:function:: get_config() -> Config + + +.. py:function:: get_user_config() -> Config + + +.. py:data:: debug + :annotation: = False + + + +.. py:function:: dump_config(config: Config, compact: bool = False, indent: int = 4) -> str + + +.. py:function:: save_config(filename: Union[os.PathLike, str], config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None) + + +.. py:function:: save_user_config(filename: Optional[Union[os.PathLike, str]] = None, user_config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None) + + +.. py:function:: get_executable_from_conda_envname(envname: str) -> str + + +.. py:function:: get_executable_from_conda_envpath(envpath: str) -> str + + +.. py:function:: get_executable_from_executable_config(executable_config: Config) -> Optional[str] + + +.. py:function:: get_32bit_executable() -> Optional[str] + + +.. py:function:: get_64bit_executable() -> Optional[str] + + diff --git a/_sources/autoapi/koapy/index.rst b/_sources/autoapi/koapy/index.rst new file mode 100644 index 00000000..582830c3 --- /dev/null +++ b/_sources/autoapi/koapy/index.rst @@ -0,0 +1,33 @@ +:py:mod:`koapy` +=============== + +.. py:module:: koapy + +.. autoapi-nested-parse:: + + Top-level package for KOAPY. + + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + backend/index.rst + backtrader/index.rst + cli/index.rst + compat/index.rst + utils/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + config/index.rst + + diff --git a/_sources/autoapi/koapy/utils/builtin/index.rst b/_sources/autoapi/koapy/utils/builtin/index.rst new file mode 100644 index 00000000..1a5d43aa --- /dev/null +++ b/_sources/autoapi/koapy/utils/builtin/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.utils.builtin` +============================= + +.. py:module:: koapy.utils.builtin + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.builtin.dir_public + + + +.. py:function:: dir_public(*args) + + diff --git a/_sources/autoapi/koapy/utils/ctypes/index.rst b/_sources/autoapi/koapy/utils/ctypes/index.rst new file mode 100644 index 00000000..e2d1b062 --- /dev/null +++ b/_sources/autoapi/koapy/utils/ctypes/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.utils.ctypes` +============================ + +.. py:module:: koapy.utils.ctypes + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.ctypes.is_admin + + + +.. py:function:: is_admin() + + diff --git a/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.rst b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.rst new file mode 100644 index 00000000..aa90a107 --- /dev/null +++ b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.rst @@ -0,0 +1,45 @@ +:py:mod:`koapy.utils.data.KrxHistoricalDailyPriceDataDownloader` +================================================================ + +.. py:module:: koapy.utils.data.KrxHistoricalDailyPriceDataDownloader + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader.KrxHistoricalDailyPriceDataDownloader + + + + +.. py:class:: KrxHistoricalDailyPriceDataDownloader + + .. py:method:: get_stocks(self) + + + .. py:method:: get_stocks_delisted(self) + + + .. py:method:: stocks(self) + :property: + + + .. py:method:: stocks_delisted(self) + :property: + + + .. py:method:: get_full_code(self, symbol) + + + .. py:method:: get_name(self, symbol) + + + .. py:method:: download(self, symbol, start_date=None, end_date=None) + + + diff --git a/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.rst b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.rst new file mode 100644 index 00000000..d4745270 --- /dev/null +++ b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.rst @@ -0,0 +1,42 @@ +:py:mod:`koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader` +======================================================================= + +.. py:module:: koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader.KrxHistoricalDailyPriceDataForBacktestLoader + + + + +.. py:class:: KrxHistoricalDailyPriceDataForBacktestLoader(filename, library=None) + + .. py:method:: get_adjust_ratios(cls, data, sort=True) + :classmethod: + + + .. py:method:: adjust_data(cls, data, sort=True) + :classmethod: + + + .. py:method:: get_symbols(self) + + + .. py:method:: update(self, download=False, progress_bar=False) + + + .. py:method:: load(self, symbol, start_time=None, end_time=None) + + + .. py:method:: load_as_cursor(self, symbol, start_time=None, end_time=None) + + + diff --git a/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.rst b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.rst new file mode 100644 index 00000000..7fa6359f --- /dev/null +++ b/_sources/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.rst @@ -0,0 +1,42 @@ +:py:mod:`koapy.utils.data.KrxHistoricalDailyPriceDataLoader` +============================================================ + +.. py:module:: koapy.utils.data.KrxHistoricalDailyPriceDataLoader + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.data.KrxHistoricalDailyPriceDataLoader.KrxHistoricalDailyPriceDataLoader + + + + +.. py:class:: KrxHistoricalDailyPriceDataLoader(filename, library=None, library_delisted=None) + + .. py:method:: symbols(self) + :property: + + + .. py:method:: symbols_delisted(self) + :property: + + + .. py:method:: load_from_database(self, symbol, is_delisted=None) + + + .. py:method:: load_or_download(self, symbol, is_delisted=None, start_date=None, end_date=None) + + + .. py:method:: load(self, symbol, is_delisted=None, start_date=None, end_date=None, download=True) + + + .. py:method:: update(self, progress_bar=False) + + + diff --git a/_sources/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.rst b/_sources/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.rst new file mode 100644 index 00000000..da20ed63 --- /dev/null +++ b/_sources/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.rst @@ -0,0 +1,25 @@ +:py:mod:`koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader` +============================================================================ + +.. py:module:: koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader.YahooFinanceKrxHistoricalDailyPriceDataDownloader + + + + +.. py:class:: YahooFinanceKrxHistoricalDailyPriceDataDownloader + + .. py:method:: download(self, symbol, start_date=None, end_date=None) + + + diff --git a/_sources/autoapi/koapy/utils/data/index.rst b/_sources/autoapi/koapy/utils/data/index.rst new file mode 100644 index 00000000..7c73da04 --- /dev/null +++ b/_sources/autoapi/koapy/utils/data/index.rst @@ -0,0 +1,105 @@ +:py:mod:`koapy.utils.data` +========================== + +.. py:module:: koapy.utils.data + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + KrxHistoricalDailyPriceDataDownloader/index.rst + KrxHistoricalDailyPriceDataForBacktestLoader/index.rst + KrxHistoricalDailyPriceDataLoader/index.rst + YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.rst + + +Package Contents +---------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader + koapy.utils.data.KrxHistoricalDailyPriceDataLoader + + + + +.. py:class:: KrxHistoricalDailyPriceDataDownloader + + .. py:method:: get_stocks(self) + + + .. py:method:: get_stocks_delisted(self) + + + .. py:method:: stocks(self) + :property: + + + .. py:method:: stocks_delisted(self) + :property: + + + .. py:method:: get_full_code(self, symbol) + + + .. py:method:: get_name(self, symbol) + + + .. py:method:: download(self, symbol, start_date=None, end_date=None) + + + +.. py:class:: KrxHistoricalDailyPriceDataForBacktestLoader(filename, library=None) + + .. py:method:: get_adjust_ratios(cls, data, sort=True) + :classmethod: + + + .. py:method:: adjust_data(cls, data, sort=True) + :classmethod: + + + .. py:method:: get_symbols(self) + + + .. py:method:: update(self, download=False, progress_bar=False) + + + .. py:method:: load(self, symbol, start_time=None, end_time=None) + + + .. py:method:: load_as_cursor(self, symbol, start_time=None, end_time=None) + + + +.. py:class:: KrxHistoricalDailyPriceDataLoader(filename, library=None, library_delisted=None) + + .. py:method:: symbols(self) + :property: + + + .. py:method:: symbols_delisted(self) + :property: + + + .. py:method:: load_from_database(self, symbol, is_delisted=None) + + + .. py:method:: load_or_download(self, symbol, is_delisted=None, start_date=None, end_date=None) + + + .. py:method:: load(self, symbol, is_delisted=None, start_date=None, end_date=None, download=True) + + + .. py:method:: update(self, progress_bar=False) + + + diff --git a/_sources/autoapi/koapy/utils/datetime/index.rst b/_sources/autoapi/koapy/utils/datetime/index.rst new file mode 100644 index 00000000..7c428b5c --- /dev/null +++ b/_sources/autoapi/koapy/utils/datetime/index.rst @@ -0,0 +1,26 @@ +:py:mod:`koapy.utils.datetime` +============================== + +.. py:module:: koapy.utils.datetime + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.datetime.is_naive + koapy.utils.datetime.localize + + + +.. py:function:: is_naive(dt) + + +.. py:function:: localize(dt, tz) + + diff --git a/_sources/autoapi/koapy/utils/exchange_calendars/index.rst b/_sources/autoapi/koapy/utils/exchange_calendars/index.rst new file mode 100644 index 00000000..4d30fe5d --- /dev/null +++ b/_sources/autoapi/koapy/utils/exchange_calendars/index.rst @@ -0,0 +1,51 @@ +:py:mod:`koapy.utils.exchange_calendars` +======================================== + +.. py:module:: koapy.utils.exchange_calendars + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.exchange_calendars.is_currently_in_session + koapy.utils.exchange_calendars.get_last_session_date + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.exchange_calendars.name + koapy.utils.exchange_calendars.calendar + koapy.utils.exchange_calendars.day + + +.. py:data:: name + :annotation: = XKRX + + + +.. py:data:: calendar + + + + +.. py:data:: day + + + + +.. py:function:: is_currently_in_session() -> bool + + +.. py:function:: get_last_session_date() -> pandas.Timestamp + + diff --git a/_sources/autoapi/koapy/utils/grpc/index.rst b/_sources/autoapi/koapy/utils/grpc/index.rst new file mode 100644 index 00000000..d9fb94d6 --- /dev/null +++ b/_sources/autoapi/koapy/utils/grpc/index.rst @@ -0,0 +1,34 @@ +:py:mod:`koapy.utils.grpc` +========================== + +.. py:module:: koapy.utils.grpc + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.grpc.warn_on_rpc_error_context + koapy.utils.grpc.warn_on_rpc_error + koapy.utils.grpc.cancel_after + koapy.utils.grpc.pprint_message + + + +.. py:function:: warn_on_rpc_error_context() + + +.. py:function:: warn_on_rpc_error(stream) + + +.. py:function:: cancel_after(stream, after) + + +.. py:function:: pprint_message(message) + + diff --git a/_sources/autoapi/koapy/utils/index.rst b/_sources/autoapi/koapy/utils/index.rst new file mode 100644 index 00000000..ad099837 --- /dev/null +++ b/_sources/autoapi/koapy/utils/index.rst @@ -0,0 +1,41 @@ +:py:mod:`koapy.utils` +===================== + +.. py:module:: koapy.utils + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + data/index.rst + logging/index.rst + messaging/index.rst + rate_limiting/index.rst + store/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + builtin/index.rst + ctypes/index.rst + datetime/index.rst + exchange_calendars/index.rst + grpc/index.rst + itertools/index.rst + networking/index.rst + notimplemented/index.rst + platform/index.rst + pywin32/index.rst + recursion/index.rst + serialization/index.rst + subprocess/index.rst + threading/index.rst + + diff --git a/_sources/autoapi/koapy/utils/itertools/index.rst b/_sources/autoapi/koapy/utils/itertools/index.rst new file mode 100644 index 00000000..313b19c2 --- /dev/null +++ b/_sources/autoapi/koapy/utils/itertools/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.utils.itertools` +=============================== + +.. py:module:: koapy.utils.itertools + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.itertools.chunk + + + +.. py:function:: chunk(iterable, n) + + diff --git a/_sources/autoapi/koapy/utils/logging/Logging/index.rst b/_sources/autoapi/koapy/utils/logging/Logging/index.rst new file mode 100644 index 00000000..e631e5e9 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/Logging/index.rst @@ -0,0 +1,66 @@ +:py:mod:`koapy.utils.logging.Logging` +===================================== + +.. py:module:: koapy.utils.logging.Logging + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.Logging.LoggingMeta + koapy.utils.logging.Logging.Logging + + + + +.. py:class:: LoggingMeta(cls, clsname, bases, dct) + + Bases: :py:obj:`type` + + .. py:method:: get_logger(cls, name=None) + + + .. py:method:: get_class_logger(cls) + + + .. py:method:: get_module_logger(cls) + + + .. py:method:: get_package_logger(cls) + + + .. py:method:: logger(cls) + :property: + + + .. py:method:: verbosity_to_loglevel(cls, verbosity) + + + .. py:method:: loglevel_to_verbosity(cls, loglevel) + + + .. py:method:: set_loglevel(cls, loglevel=logging.WARNING) + + + .. py:method:: set_verbosity(cls, verbosity=0) + + + .. py:method:: get_loglevel(cls) + + + .. py:method:: get_verbosity(cls) + + + +.. py:class:: Logging + + .. py:method:: logger(self) + :property: + + + diff --git a/_sources/autoapi/koapy/utils/logging/index.rst b/_sources/autoapi/koapy/utils/logging/index.rst new file mode 100644 index 00000000..ac33ad94 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/index.rst @@ -0,0 +1,84 @@ +:py:mod:`koapy.utils.logging` +============================= + +.. py:module:: koapy.utils.logging + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + pyside2/index.rst + tqdm/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + Logging/index.rst + + +Package Contents +---------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.Logging + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.get_logger + koapy.utils.logging.verbosity_to_loglevel + koapy.utils.logging.loglevel_to_verbosity + koapy.utils.logging.get_package_logger + koapy.utils.logging.set_loglevel + koapy.utils.logging.set_verbosity + koapy.utils.logging.get_loglevel + koapy.utils.logging.get_verbosity + + + +.. py:class:: Logging + + .. py:method:: logger(self) + :property: + + + +.. py:function:: get_logger(name=None) + + +.. py:function:: verbosity_to_loglevel(verbosity) + + +.. py:function:: loglevel_to_verbosity(loglevel) + + +.. py:function:: get_package_logger() + + +.. py:function:: set_loglevel(loglevel) + + +.. py:function:: set_verbosity(verbosity) + + +.. py:function:: get_loglevel() + + +.. py:function:: get_verbosity() + + diff --git a/_sources/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.rst b/_sources/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.rst new file mode 100644 index 00000000..d9565c59 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.logging.pyside2.QAbstractSocketLogging` +============================================================ + +.. py:module:: koapy.utils.logging.pyside2.QAbstractSocketLogging + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLoggingMeta + koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLogging + + + + +.. py:class:: QAbstractSocketLoggingMeta(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`QAbstractSocket`\ ) + + +.. py:class:: QAbstractSocketLogging(*args, **kwargs) + + Bases: :py:obj:`koapy.compat.pyside2.QtNetwork.QAbstractSocket`, :py:obj:`koapy.utils.logging.Logging.Logging` + + diff --git a/_sources/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.rst b/_sources/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.rst new file mode 100644 index 00000000..c38fb5d5 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.logging.pyside2.QObjectLogging` +==================================================== + +.. py:module:: koapy.utils.logging.pyside2.QObjectLogging + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.pyside2.QObjectLogging.QObjectLoggingMeta + koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging + + + + +.. py:class:: QObjectLoggingMeta(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`QObject`\ ) + + +.. py:class:: QObjectLogging(*args, **kwargs) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QObject`, :py:obj:`koapy.utils.logging.Logging.Logging` + + diff --git a/_sources/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.rst b/_sources/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.rst new file mode 100644 index 00000000..0d59e7c2 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.logging.pyside2.QThreadLogging` +==================================================== + +.. py:module:: koapy.utils.logging.pyside2.QThreadLogging + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.pyside2.QThreadLogging.QThreadLoggingMeta + koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging + + + + +.. py:class:: QThreadLoggingMeta(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`QThread`\ ) + + +.. py:class:: QThreadLogging(*args, **kwargs) + + Bases: :py:obj:`koapy.compat.pyside2.QtCore.QThread`, :py:obj:`koapy.utils.logging.Logging.Logging` + + diff --git a/_sources/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.rst b/_sources/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.rst new file mode 100644 index 00000000..43c142a7 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.logging.pyside2.QWidgetLogging` +==================================================== + +.. py:module:: koapy.utils.logging.pyside2.QWidgetLogging + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLoggingMeta + koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging + + + + +.. py:class:: QWidgetLoggingMeta(cls, clsname, bases, dct) + + Bases: :py:obj:`type`\ (\ :py:obj:`Logging`\ ), :py:obj:`type`\ (\ :py:obj:`QWidget`\ ) + + +.. py:class:: QWidgetLogging(*args, **kwargs) + + Bases: :py:obj:`koapy.compat.pyside2.QtWidgets.QWidget`, :py:obj:`koapy.utils.logging.Logging.Logging` + + diff --git a/_sources/autoapi/koapy/utils/logging/pyside2/index.rst b/_sources/autoapi/koapy/utils/logging/pyside2/index.rst new file mode 100644 index 00000000..5164ec43 --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/pyside2/index.rst @@ -0,0 +1,18 @@ +:py:mod:`koapy.utils.logging.pyside2` +===================================== + +.. py:module:: koapy.utils.logging.pyside2 + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + QAbstractSocketLogging/index.rst + QObjectLogging/index.rst + QThreadLogging/index.rst + QWidgetLogging/index.rst + + diff --git a/_sources/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.rst b/_sources/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.rst new file mode 100644 index 00000000..60fc1e3e --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.rst @@ -0,0 +1,28 @@ +:py:mod:`koapy.utils.logging.tqdm.TqdmStreamHandler` +==================================================== + +.. py:module:: koapy.utils.logging.tqdm.TqdmStreamHandler + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.logging.tqdm.TqdmStreamHandler.TqdmStreamHandler + + + + +.. py:class:: TqdmStreamHandler(stream=None) + + Bases: :py:obj:`logging.StreamHandler` + + A handler class which writes logging records, appropriately formatted, + to a stream. Note that this class does not close the stream, as + sys.stdout or sys.stderr may be used. + + diff --git a/_sources/autoapi/koapy/utils/logging/tqdm/index.rst b/_sources/autoapi/koapy/utils/logging/tqdm/index.rst new file mode 100644 index 00000000..74ef5c8b --- /dev/null +++ b/_sources/autoapi/koapy/utils/logging/tqdm/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.utils.logging.tqdm` +================================== + +.. py:module:: koapy.utils.logging.tqdm + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + TqdmStreamHandler/index.rst + + diff --git a/_sources/autoapi/koapy/utils/messaging/DiscordMessenger/index.rst b/_sources/autoapi/koapy/utils/messaging/DiscordMessenger/index.rst new file mode 100644 index 00000000..0e03b529 --- /dev/null +++ b/_sources/autoapi/koapy/utils/messaging/DiscordMessenger/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.utils.messaging.DiscordMessenger` +================================================ + +.. py:module:: koapy.utils.messaging.DiscordMessenger + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.messaging.DiscordMessenger.DiscordWebhookMessenger + koapy.utils.messaging.DiscordMessenger.DoItYourselfDiscordWebhookMessenger + + + + +.. py:class:: DiscordWebhookMessenger(url=None) + + Bases: :py:obj:`koapy.utils.messaging.Messenger.Messenger` + + .. py:method:: send_message(self, content) + + + +.. py:class:: DoItYourselfDiscordWebhookMessenger(url=None) + + Bases: :py:obj:`koapy.utils.messaging.Messenger.Messenger` + + .. py:method:: send_message(self, content) + + + diff --git a/_sources/autoapi/koapy/utils/messaging/Messenger/index.rst b/_sources/autoapi/koapy/utils/messaging/Messenger/index.rst new file mode 100644 index 00000000..2ceed099 --- /dev/null +++ b/_sources/autoapi/koapy/utils/messaging/Messenger/index.rst @@ -0,0 +1,28 @@ +:py:mod:`koapy.utils.messaging.Messenger` +========================================= + +.. py:module:: koapy.utils.messaging.Messenger + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.messaging.Messenger.Messenger + + + + +.. py:class:: Messenger + + Bases: :py:obj:`abc.ABC` + + .. py:method:: send_message(self, content) + :abstractmethod: + + + diff --git a/_sources/autoapi/koapy/utils/messaging/index.rst b/_sources/autoapi/koapy/utils/messaging/index.rst new file mode 100644 index 00000000..e66d26ed --- /dev/null +++ b/_sources/autoapi/koapy/utils/messaging/index.rst @@ -0,0 +1,16 @@ +:py:mod:`koapy.utils.messaging` +=============================== + +.. py:module:: koapy.utils.messaging + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + DiscordMessenger/index.rst + Messenger/index.rst + + diff --git a/_sources/autoapi/koapy/utils/networking/index.rst b/_sources/autoapi/koapy/utils/networking/index.rst new file mode 100644 index 00000000..7291aca3 --- /dev/null +++ b/_sources/autoapi/koapy/utils/networking/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.networking` +================================ + +.. py:module:: koapy.utils.networking + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.networking.find_free_port_for_host + koapy.utils.networking.get_free_localhost_port + koapy.utils.networking.is_in_private_network + + + +.. py:function:: find_free_port_for_host(host) + + +.. py:function:: get_free_localhost_port() + + +.. py:function:: is_in_private_network(host) + + diff --git a/_sources/autoapi/koapy/utils/notimplemented/index.rst b/_sources/autoapi/koapy/utils/notimplemented/index.rst new file mode 100644 index 00000000..a5c8cfe0 --- /dev/null +++ b/_sources/autoapi/koapy/utils/notimplemented/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.notimplemented` +==================================== + +.. py:module:: koapy.utils.notimplemented + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.notimplemented.notimplemented + koapy.utils.notimplemented.isnotimplemented + koapy.utils.notimplemented.isimplemented + + + +.. py:function:: notimplemented(func) + + +.. py:function:: isnotimplemented(func) + + +.. py:function:: isimplemented(func) + + diff --git a/_sources/autoapi/koapy/utils/platform/index.rst b/_sources/autoapi/koapy/utils/platform/index.rst new file mode 100644 index 00000000..e856902a --- /dev/null +++ b/_sources/autoapi/koapy/utils/platform/index.rst @@ -0,0 +1,30 @@ +:py:mod:`koapy.utils.platform` +============================== + +.. py:module:: koapy.utils.platform + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.platform.is_windows + koapy.utils.platform.is_32bit + koapy.utils.platform.is_64bit + + + +.. py:function:: is_windows() + + +.. py:function:: is_32bit() + + +.. py:function:: is_64bit() + + diff --git a/_sources/autoapi/koapy/utils/pywin32/index.rst b/_sources/autoapi/koapy/utils/pywin32/index.rst new file mode 100644 index 00000000..79303e1e --- /dev/null +++ b/_sources/autoapi/koapy/utils/pywin32/index.rst @@ -0,0 +1,71 @@ +:py:mod:`koapy.utils.pywin32` +============================= + +.. py:module:: koapy.utils.pywin32 + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.pywin32.IsPyIID + koapy.utils.pywin32.IsPyITypeLib + koapy.utils.pywin32.IsPyIIDLike + koapy.utils.pywin32.GetTypelibSpecs + koapy.utils.pywin32.GetLatestTypelibSpec + koapy.utils.pywin32.LoadTypeLib + koapy.utils.pywin32.BuildOleItems + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.pywin32.PyIID + koapy.utils.pywin32.PyITypeLib + koapy.utils.pywin32.PyIIDLike + + +.. py:data:: PyIID + + + + +.. py:data:: PyITypeLib + :annotation: = PyITypeLib + + + +.. py:data:: PyIIDLike + + + + +.. py:function:: IsPyIID(value) -> TypeGuard[PyIID] + + +.. py:function:: IsPyITypeLib(value) -> TypeGuard[PyITypeLib] + + +.. py:function:: IsPyIIDLike(value) -> TypeGuard[PyIIDLike] + + +.. py:function:: GetTypelibSpecs(iid: PyIIDLike) -> List[win32com.client.selecttlb.TypelibSpec] + + +.. py:function:: GetLatestTypelibSpec(specs: Union[Sequence[win32com.client.selecttlb.TypelibSpec], PyIIDLike]) -> Optional[win32com.client.selecttlb.TypelibSpec] + + +.. py:function:: LoadTypeLib(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike]) -> Optional[PyITypeLib] + + +.. py:function:: BuildOleItems(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike], tlb: Optional[PyITypeLib] = None) -> Tuple[Dict[PyIID, win32com.client.genpy.DispatchItem], Dict[PyIID, win32com.client.genpy.EnumerationItem], Dict[PyIID, win32com.client.genpy.RecordItem], Dict[PyIID, win32com.client.genpy.VTableItem]] + + diff --git a/_sources/autoapi/koapy/utils/rate_limiting/RateLimiter/index.rst b/_sources/autoapi/koapy/utils/rate_limiting/RateLimiter/index.rst new file mode 100644 index 00000000..70fe4f7e --- /dev/null +++ b/_sources/autoapi/koapy/utils/rate_limiting/RateLimiter/index.rst @@ -0,0 +1,64 @@ +:py:mod:`koapy.utils.rate_limiting.RateLimiter` +=============================================== + +.. py:module:: koapy.utils.rate_limiting.RateLimiter + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.rate_limiting.RateLimiter.RateLimiter + koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter + koapy.utils.rate_limiting.RateLimiter.CompositeTimeWindowRateLimiter + + + + +.. py:class:: RateLimiter + + .. py:method:: check_sleep_seconds(self, *args, **kwargs) + + + .. py:method:: add_call_history(self, *args, **kwargs) + + + .. py:method:: sleep_if_necessary(self, *args, **kwargs) + + + .. py:method:: wrap(self, func) + + + +.. py:class:: TimeWindowRateLimiter(period, calls) + + Bases: :py:obj:`RateLimiter`, :py:obj:`koapy.utils.logging.Logging.Logging` + + .. py:method:: check_sleep_seconds(self, *args, **kwargs) + + + .. py:method:: add_call_history(self, *args, **kwargs) + + + .. py:method:: sleep_if_necessary(self, *args, **kwargs) + + + +.. py:class:: CompositeTimeWindowRateLimiter(limiters: List[RateLimiter]) + + Bases: :py:obj:`RateLimiter` + + .. py:method:: check_sleep_seconds(self, *args, **kwargs) + + + .. py:method:: add_call_history(self, *args, **kwargs) + + + .. py:method:: sleep_if_necessary(self, *args, **kwargs) + + + diff --git a/_sources/autoapi/koapy/utils/rate_limiting/index.rst b/_sources/autoapi/koapy/utils/rate_limiting/index.rst new file mode 100644 index 00000000..b8a863b2 --- /dev/null +++ b/_sources/autoapi/koapy/utils/rate_limiting/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.utils.rate_limiting` +=================================== + +.. py:module:: koapy.utils.rate_limiting + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + pyside2/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + RateLimiter/index.rst + + diff --git a/_sources/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst b/_sources/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst new file mode 100644 index 00000000..0e1a8a40 --- /dev/null +++ b/_sources/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst @@ -0,0 +1,94 @@ +:py:mod:`koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor` +================================================================ + +.. py:module:: koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorRunnable + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorDecoratedFunction + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutor + + + + +.. py:class:: QRateLimitedExecutorRunnable(limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Union[Tuple[Any], List[Any]], kwargs: Dict[str, Any]) + + .. py:method:: check_sleep_seconds(self) + + + .. py:method:: add_call_history(self) + + + .. py:method:: sleep_if_necessary(self) + + + .. py:method:: run(self) + + + .. py:method:: cancel(self) + + + .. py:method:: result(self) + + + +.. py:class:: QRateLimitedExecutorDecoratedFunction(func, limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, executor: concurrent.futures.Executor) + + .. py:method:: call(self, *args, **kwargs) + + + .. py:method:: async_call(self, *args, **kwargs) + + + +.. py:class:: QRateLimitedExecutor(limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None) + + Bases: :py:obj:`koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging`, :py:obj:`concurrent.futures.Executor` + + This is an abstract base class for concrete asynchronous executors. + + .. py:attribute:: readyRunnable + + + + + .. py:method:: run(self) + + + .. py:method:: onReadyRunnable(self, runnable: QRateLimitedExecutorRunnable) + + + .. py:method:: submit(self, fn: Callable[Ellipsis, Any], *args, **kwargs) + + Submits a callable to be executed with the given arguments. + + Schedules the callable to be executed as fn(*args, **kwargs) and returns + a Future instance representing the execution of the callable. + + :returns: A Future representing the given call. + + + .. py:method:: shutdown(self, wait: bool = True, cancel_futures: bool = False) + + Clean-up the resources associated with the Executor. + + It is safe to call this method several times. Otherwise, no other + methods can be called after this one. + + :param wait: If True then shutdown will not return until all running + futures have finished executing and the resources used by the + executor have been reclaimed. + + + .. py:method:: wrap(self, func: Callable[Ellipsis, Any]) + + + diff --git a/_sources/autoapi/koapy/utils/rate_limiting/pyside2/index.rst b/_sources/autoapi/koapy/utils/rate_limiting/pyside2/index.rst new file mode 100644 index 00000000..89886b88 --- /dev/null +++ b/_sources/autoapi/koapy/utils/rate_limiting/pyside2/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.utils.rate_limiting.pyside2` +=========================================== + +.. py:module:: koapy.utils.rate_limiting.pyside2 + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + QRateLimitedExecutor/index.rst + + diff --git a/_sources/autoapi/koapy/utils/recursion/index.rst b/_sources/autoapi/koapy/utils/recursion/index.rst new file mode 100644 index 00000000..8f3a2793 --- /dev/null +++ b/_sources/autoapi/koapy/utils/recursion/index.rst @@ -0,0 +1,24 @@ +:py:mod:`koapy.utils.recursion` +=============================== + +.. py:module:: koapy.utils.recursion + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.recursion.depth + + + +.. py:function:: depth() + + return recursion depth. 0 if no recursion + + diff --git a/_sources/autoapi/koapy/utils/serialization/index.rst b/_sources/autoapi/koapy/utils/serialization/index.rst new file mode 100644 index 00000000..47cedca6 --- /dev/null +++ b/_sources/autoapi/koapy/utils/serialization/index.rst @@ -0,0 +1,36 @@ +:py:mod:`koapy.utils.serialization` +=================================== + +.. py:module:: koapy.utils.serialization + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.serialization.JsonSerializable + + + + +.. py:class:: JsonSerializable + + .. py:method:: to_dict(self) + + + .. py:method:: from_dict(cls, dic) + :classmethod: + + + .. py:method:: to_json(self, f=None, encoding=None) + + + .. py:method:: from_json(cls, jsn, encoding=None) + :classmethod: + + + diff --git a/_sources/autoapi/koapy/utils/store/SQLiteFileLibrary/index.rst b/_sources/autoapi/koapy/utils/store/SQLiteFileLibrary/index.rst new file mode 100644 index 00000000..8cab8a30 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/SQLiteFileLibrary/index.rst @@ -0,0 +1,43 @@ +:py:mod:`koapy.utils.store.SQLiteFileLibrary` +============================================= + +.. py:module:: koapy.utils.store.SQLiteFileLibrary + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.SQLiteFileLibrary.SQLiteFileLibrary + + + + +.. py:class:: SQLiteFileLibrary(filename) + + .. py:method:: list_symbols(self) + + + .. py:method:: has_symbol(self, symbol) + + + .. py:method:: write(self, symbol, data) + + + .. py:method:: read_as_dataframe(self, symbol, time_column=None, start_time=None, end_time=None) + + + .. py:method:: read_as_cursor(self, symbol, time_column=None, start_time=None, end_time=None) + + + .. py:method:: read(self, *args, **kwargs) + + + .. py:method:: delete(self, symbol) + + + diff --git a/_sources/autoapi/koapy/utils/store/SQLiteStore/index.rst b/_sources/autoapi/koapy/utils/store/SQLiteStore/index.rst new file mode 100644 index 00000000..16f67439 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/SQLiteStore/index.rst @@ -0,0 +1,40 @@ +:py:mod:`koapy.utils.store.SQLiteStore` +======================================= + +.. py:module:: koapy.utils.store.SQLiteStore + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.SQLiteStore.SQLiteStore + + + + +.. py:class:: SQLiteStore(filename) + + .. py:method:: list_libraries(self) + + + .. py:method:: library_exists(self, library) + + + .. py:method:: initialize_library(self, library) + + + .. py:method:: get_library(self, library) + + + .. py:method:: get_or_create_library(self, library) + + + .. py:method:: delete_library(self, library) + + + diff --git a/_sources/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.rst b/_sources/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.rst new file mode 100644 index 00000000..ef013066 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.rst @@ -0,0 +1,55 @@ +:py:mod:`koapy.utils.store.SQLiteStoreLibrary` +============================================== + +.. py:module:: koapy.utils.store.SQLiteStoreLibrary + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.SQLiteStoreLibrary.SQLiteStoreLibrary + + + + +.. py:class:: SQLiteStoreLibrary(store, library) + + .. py:method:: list_symbols(self, all_symbols=False, snapshot=None) + + + .. py:method:: has_symbol(self, symbol) + + + .. py:method:: list_versions(self, symbol=None, snapshot=None, latest_only=False) + + + .. py:method:: write(self, symbol, data, metadata=None, prune_previous_version=True, **kwargs) + + + .. py:method:: read_as_dataframe(self, symbol, as_of=None, time_column=None, start_time=None, end_time=None) + + + .. py:method:: read_as_cursor(self, symbol, as_of=None, time_column=None, start_time=None, end_time=None) + + + .. py:method:: read(self, *args, **kwargs) + + + .. py:method:: delete(self, symbol) + + + .. py:method:: list_snapshots(self) + + + .. py:method:: snapshot(self, snapshot) + + + .. py:method:: delete_snapshot(self, snapshot) + + + diff --git a/_sources/autoapi/koapy/utils/store/index.rst b/_sources/autoapi/koapy/utils/store/index.rst new file mode 100644 index 00000000..8522dc2a --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/index.rst @@ -0,0 +1,61 @@ +:py:mod:`koapy.utils.store` +=========================== + +.. py:module:: koapy.utils.store + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + misc/index.rst + sqlalchemy/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + SQLiteFileLibrary/index.rst + SQLiteStore/index.rst + SQLiteStoreLibrary/index.rst + + +Package Contents +---------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.SQLiteStore + + + + +.. py:class:: SQLiteStore(filename) + + .. py:method:: list_libraries(self) + + + .. py:method:: library_exists(self, library) + + + .. py:method:: initialize_library(self, library) + + + .. py:method:: get_library(self, library) + + + .. py:method:: get_or_create_library(self, library) + + + .. py:method:: delete_library(self, library) + + + diff --git a/_sources/autoapi/koapy/utils/store/misc/VersionedItem/index.rst b/_sources/autoapi/koapy/utils/store/misc/VersionedItem/index.rst new file mode 100644 index 00000000..b6be6b91 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/misc/VersionedItem/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.utils.store.misc.VersionedItem` +============================================== + +.. py:module:: koapy.utils.store.misc.VersionedItem + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.misc.VersionedItem.VersionedItem + + + + +.. py:class:: VersionedItem(library, symbol, version, timestamp, data, metadata) + + diff --git a/_sources/autoapi/koapy/utils/store/misc/index.rst b/_sources/autoapi/koapy/utils/store/misc/index.rst new file mode 100644 index 00000000..db0f9425 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/misc/index.rst @@ -0,0 +1,15 @@ +:py:mod:`koapy.utils.store.misc` +================================ + +.. py:module:: koapy.utils.store.misc + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + VersionedItem/index.rst + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Base/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Base/index.rst new file mode 100644 index 00000000..a8ee4e84 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Base/index.rst @@ -0,0 +1,14 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Base` +=========================================== + +.. py:module:: koapy.utils.store.sqlalchemy.Base + + +Module Contents +--------------- + +.. py:data:: Base + + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Library/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Library/index.rst new file mode 100644 index 00000000..38175ad9 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Library/index.rst @@ -0,0 +1,68 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Library` +============================================== + +.. py:module:: koapy.utils.store.sqlalchemy.Library + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.Library.Library + + + + +.. py:class:: Library + + Bases: :py:obj:`koapy.utils.store.sqlalchemy.Base.Base` + + .. py:attribute:: id + + + + + .. py:attribute:: name + + + + + .. py:attribute:: symbols + + + + + .. py:attribute:: snapshots + + + + + .. py:method:: get_symbol(self, symbol, deleted=False) + + + .. py:method:: get_or_create_symbol(self, symbol) + + + .. py:method:: get_symbols(self, deleted=False) + + + .. py:method:: get_versions(self, deleted=False) + + + .. py:method:: get_latest_versions(self, deleted=False) + + + .. py:method:: get_snapshot(self, snapshot) + + + .. py:method:: create_snapshot(self, snapshot) + + + .. py:method:: delete(self) + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Session/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Session/index.rst new file mode 100644 index 00000000..1f84a044 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Session/index.rst @@ -0,0 +1,14 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Session` +============================================== + +.. py:module:: koapy.utils.store.sqlalchemy.Session + + +Module Contents +--------------- + +.. py:data:: Session + + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.rst new file mode 100644 index 00000000..1caefe78 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.rst @@ -0,0 +1,66 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Snapshot` +=============================================== + +.. py:module:: koapy.utils.store.sqlalchemy.Snapshot + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.Snapshot.Snapshot + + + + +.. py:class:: Snapshot + + Bases: :py:obj:`koapy.utils.store.sqlalchemy.Base.Base` + + .. py:attribute:: id + + + + + .. py:attribute:: name + + + + + .. py:attribute:: timestamp + + + + + .. py:attribute:: library_id + + + + + .. py:attribute:: library + + + + + .. py:attribute:: versions + + + + + .. py:method:: get_symbols(self) + + + .. py:method:: get_versions(self) + + + .. py:method:: get_version_of_symbol(self, symbol) + + + .. py:method:: delete(self) + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.rst new file mode 100644 index 00000000..bec8f489 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.rst @@ -0,0 +1,44 @@ +:py:mod:`koapy.utils.store.sqlalchemy.SnapshotAssociation` +========================================================== + +.. py:module:: koapy.utils.store.sqlalchemy.SnapshotAssociation + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.SnapshotAssociation.SnapshotAssociation + + + + +.. py:class:: SnapshotAssociation + + Bases: :py:obj:`koapy.utils.store.sqlalchemy.Base.Base` + + .. py:attribute:: snapshot_id + + + + + .. py:attribute:: version_id + + + + + .. py:attribute:: snapshot + + + + + .. py:attribute:: version + + + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst new file mode 100644 index 00000000..3db303ea --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst @@ -0,0 +1,75 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Symbol` +============================================= + +.. py:module:: koapy.utils.store.sqlalchemy.Symbol + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.Symbol.Symbol + + + + +.. py:class:: Symbol + + Bases: :py:obj:`koapy.utils.store.sqlalchemy.Base.Base` + + .. py:attribute:: id + + + + + .. py:attribute:: name + + + + + .. py:attribute:: library_id + + + + + .. py:attribute:: library + + + + + .. py:attribute:: versions + + + + + .. py:method:: get_versions(self, deleted=False) + + versions = self.versions + if not deleted: + versions = [version for version in versions if not version.deleted] + + + .. py:method:: get_latest_version(self, deleted=False) + + versions = self.versions + if len(versions) == 0: + raise NoResultFound + latest_version = self.versions[-1] + if not deleted and latest_version.deleted: + raise NoResultFound + + + .. py:method:: create_new_version(self, table_name=None, user_metadata=None, pandas_metadata=None, deleted=None) + + + .. py:method:: get_version_by_number(self, version_number, deleted=False) + + + .. py:method:: get_prunable_versions(self, keep_mins=120) + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.rst new file mode 100644 index 00000000..567c136f --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.rst @@ -0,0 +1,219 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Timestamp` +================================================ + +.. py:module:: koapy.utils.store.sqlalchemy.Timestamp + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.Timestamp.Timestamp + + + + +.. py:class:: Timestamp(*args, **kwargs) + + Bases: :py:obj:`sqlalchemy.types.TypeDecorator` + + Allows the creation of types which add additional functionality + to an existing type. + + This method is preferred to direct subclassing of SQLAlchemy's + built-in types as it ensures that all required functionality of + the underlying type is kept in place. + + Typical usage:: + + import sqlalchemy.types as types + + class MyType(types.TypeDecorator): + '''Prefixes Unicode values with "PREFIX:" on the way in and + strips it off on the way out. + ''' + + impl = types.Unicode + + cache_ok = True + + def process_bind_param(self, value, dialect): + return "PREFIX:" + value + + def process_result_value(self, value, dialect): + return value[7:] + + def copy(self, **kw): + return MyType(self.impl.length) + + The class-level ``impl`` attribute is required, and can reference any + :class:`.TypeEngine` class. Alternatively, the :meth:`load_dialect_impl` + method can be used to provide different type classes based on the dialect + given; in this case, the ``impl`` variable can reference + ``TypeEngine`` as a placeholder. + + The :attr:`.TypeDecorator.cache_ok` class-level flag indicates if this + custom :class:`.TypeDecorator` is safe to be used as part of a cache key. + This flag defaults to ``None`` which will initially generate a warning + when the SQL compiler attempts to generate a cache key for a statement + that uses this type. If the :class:`.TypeDecorator` is not guaranteed + to produce the same bind/result behavior and SQL generation + every time, this flag should be set to ``False``; otherwise if the + class produces the same behavior each time, it may be set to ``True``. + See :attr:`.TypeDecorator.cache_ok` for further notes on how this works. + + Types that receive a Python type that isn't similar to the ultimate type + used may want to define the :meth:`TypeDecorator.coerce_compared_value` + method. This is used to give the expression system a hint when coercing + Python objects into bind parameters within expressions. Consider this + expression:: + + mytable.c.somecol + datetime.date(2009, 5, 15) + + Above, if "somecol" is an ``Integer`` variant, it makes sense that + we're doing date arithmetic, where above is usually interpreted + by databases as adding a number of days to the given date. + The expression system does the right thing by not attempting to + coerce the "date()" value into an integer-oriented bind parameter. + + However, in the case of ``TypeDecorator``, we are usually changing an + incoming Python type to something new - ``TypeDecorator`` by default will + "coerce" the non-typed side to be the same type as itself. Such as below, + we define an "epoch" type that stores a date value as an integer:: + + class MyEpochType(types.TypeDecorator): + impl = types.Integer + + epoch = datetime.date(1970, 1, 1) + + def process_bind_param(self, value, dialect): + return (value - self.epoch).days + + def process_result_value(self, value, dialect): + return self.epoch + timedelta(days=value) + + Our expression of ``somecol + date`` with the above type will coerce the + "date" on the right side to also be treated as ``MyEpochType``. + + This behavior can be overridden via the + :meth:`~TypeDecorator.coerce_compared_value` method, which returns a type + that should be used for the value of the expression. Below we set it such + that an integer value will be treated as an ``Integer``, and any other + value is assumed to be a date and will be treated as a ``MyEpochType``:: + + def coerce_compared_value(self, op, value): + if isinstance(value, int): + return Integer() + else: + return self + + .. warning:: + + Note that the **behavior of coerce_compared_value is not inherited + by default from that of the base type**. + If the :class:`.TypeDecorator` is augmenting a + type that requires special logic for certain types of operators, + this method **must** be overridden. A key example is when decorating + the :class:`_postgresql.JSON` and :class:`_postgresql.JSONB` types; + the default rules of :meth:`.TypeEngine.coerce_compared_value` should + be used in order to deal with operators like index operations:: + + class MyJsonType(TypeDecorator): + impl = postgresql.JSON + + cache_ok = True + + def coerce_compared_value(self, op, value): + return self.impl.coerce_compared_value(op, value) + + Without the above step, index operations such as ``mycol['foo']`` + will cause the index value ``'foo'`` to be JSON encoded. + + + .. py:attribute:: impl + + + + + .. py:attribute:: cache_ok + :annotation: = True + + + + .. py:attribute:: signature + + + + + .. py:attribute:: utc + + + + + .. py:attribute:: local_timezone + + + + + .. py:method:: is_naive(cls, value) + :classmethod: + + + .. py:method:: process_bind_param(self, value, dialect) + + Receive a bound parameter value to be converted. + + Custom subclasses of :class:`_types.TypeDecorator` should override + this method to provide custom behaviors for incoming data values. + This method is called at **statement execution time** and is passed + the literal Python data value which is to be associated with a bound + parameter in the statement. + + The operation could be anything desired to perform custom + behavior, such as transforming or serializing data. + This could also be used as a hook for validating logic. + + :param value: Data to operate upon, of any type expected by + this method in the subclass. Can be ``None``. + :param dialect: the :class:`.Dialect` in use. + + .. seealso:: + + :ref:`types_typedecorator` + + :meth:`_types.TypeDecorator.process_result_value` + + + + .. py:method:: process_result_value(self, value, dialect) + + Receive a result-row column value to be converted. + + Custom subclasses of :class:`_types.TypeDecorator` should override + this method to provide custom behaviors for data values + being received in result rows coming from the database. + This method is called at **result fetching time** and is passed + the literal Python data value that's extracted from a database result + row. + + The operation could be anything desired to perform custom + behavior, such as transforming or deserializing data. + + :param value: Data to operate upon, of any type expected by + this method in the subclass. Can be ``None``. + :param dialect: the :class:`.Dialect` in use. + + .. seealso:: + + :ref:`types_typedecorator` + + :meth:`_types.TypeDecorator.process_bind_param` + + + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/Version/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/Version/index.rst new file mode 100644 index 00000000..1015bcc5 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/Version/index.rst @@ -0,0 +1,80 @@ +:py:mod:`koapy.utils.store.sqlalchemy.Version` +============================================== + +.. py:module:: koapy.utils.store.sqlalchemy.Version + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.store.sqlalchemy.Version.Version + + + + +.. py:class:: Version + + Bases: :py:obj:`koapy.utils.store.sqlalchemy.Base.Base` + + .. py:attribute:: id + + + + + .. py:attribute:: version + + + + + .. py:attribute:: table_name + + + + + .. py:attribute:: user_metadata + + + + + .. py:attribute:: pandas_metadata + + + + + .. py:attribute:: deleted + + + + + .. py:attribute:: timestamp + + + + + .. py:attribute:: symbol_id + + + + + .. py:attribute:: symbol + + + + + .. py:attribute:: snapshots + + + + + .. py:method:: get_snapshots(self) + + + .. py:method:: delete(self) + + + diff --git a/_sources/autoapi/koapy/utils/store/sqlalchemy/index.rst b/_sources/autoapi/koapy/utils/store/sqlalchemy/index.rst new file mode 100644 index 00000000..5c06dea8 --- /dev/null +++ b/_sources/autoapi/koapy/utils/store/sqlalchemy/index.rst @@ -0,0 +1,22 @@ +:py:mod:`koapy.utils.store.sqlalchemy` +====================================== + +.. py:module:: koapy.utils.store.sqlalchemy + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + Base/index.rst + Library/index.rst + Session/index.rst + Snapshot/index.rst + SnapshotAssociation/index.rst + Symbol/index.rst + Timestamp/index.rst + Version/index.rst + + diff --git a/_sources/autoapi/koapy/utils/subprocess/index.rst b/_sources/autoapi/koapy/utils/subprocess/index.rst new file mode 100644 index 00000000..c39f0f8d --- /dev/null +++ b/_sources/autoapi/koapy/utils/subprocess/index.rst @@ -0,0 +1,86 @@ +:py:mod:`koapy.utils.subprocess` +================================ + +.. py:module:: koapy.utils.subprocess + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.subprocess.Popen + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.subprocess.function_to_script + koapy.utils.subprocess.function_to_subprocess_args + koapy.utils.subprocess.run_file + koapy.utils.subprocess.run_script + koapy.utils.subprocess.run_function + koapy.utils.subprocess.quote + koapy.utils.subprocess.run_as_admin + koapy.utils.subprocess.create_job_object_for_cleanup + koapy.utils.subprocess.make_process_die_when_parent_dies + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + koapy.utils.subprocess.logger + koapy.utils.subprocess.job_handle + + +.. py:data:: logger + + + + +.. py:function:: function_to_script(func) + + +.. py:function:: function_to_subprocess_args(func, executable=None) + + +.. py:function:: run_file(filename, *args, executable=None, **kwargs) + + +.. py:function:: run_script(script, *args, executable=None, **kwargs) + + +.. py:function:: run_function(function, *args, executable=None, **kwargs) + + +.. py:function:: quote(s) + + +.. py:function:: run_as_admin(cmd, cwd=None, check=True, wait=True) + + +.. py:function:: create_job_object_for_cleanup() + + +.. py:data:: job_handle + + + + +.. py:function:: make_process_die_when_parent_dies(pid) + + +.. py:class:: Popen(*args, **kwargs) + + Bases: :py:obj:`subprocess.Popen` + + diff --git a/_sources/autoapi/koapy/utils/threading/index.rst b/_sources/autoapi/koapy/utils/threading/index.rst new file mode 100644 index 00000000..1a98256b --- /dev/null +++ b/_sources/autoapi/koapy/utils/threading/index.rst @@ -0,0 +1,26 @@ +:py:mod:`koapy.utils.threading` +=============================== + +.. py:module:: koapy.utils.threading + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + koapy.utils.threading.Singleton + + + + +.. py:class:: Singleton + + .. py:method:: get_instance(cls, *args, **kwargs) + :classmethod: + + + diff --git a/docs/source/contributing.rst b/_sources/contributing.rst similarity index 100% rename from docs/source/contributing.rst rename to _sources/contributing.rst diff --git a/docs/source/history.rst b/_sources/history.rst similarity index 100% rename from docs/source/history.rst rename to _sources/history.rst diff --git a/docs/source/index.rst b/_sources/index.rst similarity index 100% rename from docs/source/index.rst rename to _sources/index.rst diff --git a/docs/source/installation.rst b/_sources/installation.rst similarity index 100% rename from docs/source/installation.rst rename to _sources/installation.rst diff --git a/docs/source/notebooks/getting-historical-stock-price-data.rst b/_sources/notebooks/getting-historical-stock-price-data.rst similarity index 100% rename from docs/source/notebooks/getting-historical-stock-price-data.rst rename to _sources/notebooks/getting-historical-stock-price-data.rst diff --git a/docs/source/notebooks/index.rst b/_sources/notebooks/index.rst similarity index 100% rename from docs/source/notebooks/index.rst rename to _sources/notebooks/index.rst diff --git a/docs/source/notebooks/koapy-tutorial.rst b/_sources/notebooks/koapy-tutorial.rst similarity index 100% rename from docs/source/notebooks/koapy-tutorial.rst rename to _sources/notebooks/koapy-tutorial.rst diff --git a/docs/source/readme.rst b/_sources/readme.rst similarity index 100% rename from docs/source/readme.rst rename to _sources/readme.rst diff --git a/docs/source/usage.rst b/_sources/usage.rst similarity index 100% rename from docs/source/usage.rst rename to _sources/usage.rst diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 00000000..dc404f5c --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,707 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Noto Serif KR', Georgia, 'Times New Roman', Times, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: 'Noto Serif KR', Georgia, 'Times New Roman', Times, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: 'Noto Serif KR', Georgia, 'Times New Roman', Times, serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Noto Serif KR', Georgia, 'Times New Roman', Times, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: 'Noto Serif KR', Georgia, 'Times New Roman', Times, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'D2Coding', 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: -20px -30px 20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} +@media screen and (min-width: 876px) { + div.sphinxsidebar { + position: fixed; + margin-left: 0; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..bf18350b --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,906 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/source/_static/css/style.css b/_static/css/style.css similarity index 100% rename from docs/source/_static/css/style.css rename to _static/css/style.css diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 00000000..2a924f1d --- /dev/null +++ b/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..e1bfd708 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,358 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + this.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + var url = new URL(window.location); + url.searchParams.delete('highlight'); + window.history.replaceState({}, '', url); + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar : function() { + $('input[name=q]').first().focus(); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + return; + + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON') { + if (event.altKey || event.ctrlKey || event.metaKey) + return; + + if (!event.shiftKey) { + switch (event.key) { + case 'ArrowLeft': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 'ArrowRight': + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) + break; + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + case 'Escape': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.hideSearchWords(); + return false; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case '/': + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) + break; + Documentation.focusSearchBar(); + return false; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..608119d1 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '0.8.3', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/graphviz.css b/_static/graphviz.css new file mode 100644 index 00000000..19e7afd3 --- /dev/null +++ b/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/docs/source/_static/html/notebooks/getting-historical-stock-price-data.html b/_static/html/notebooks/getting-historical-stock-price-data.html similarity index 100% rename from docs/source/_static/html/notebooks/getting-historical-stock-price-data.html rename to _static/html/notebooks/getting-historical-stock-price-data.html diff --git a/docs/source/_static/html/notebooks/koapy-tutorial.html b/_static/html/notebooks/koapy-tutorial.html similarity index 100% rename from docs/source/_static/html/notebooks/koapy-tutorial.html rename to _static/html/notebooks/koapy-tutorial.html diff --git a/_static/jquery-3.5.1.js b/_static/jquery-3.5.1.js new file mode 100644 index 00000000..50937333 --- /dev/null +++ b/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Credits

+
+

Development Lead

+ +
+
+

Contributors

+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/index.html b/autoapi/index.html new file mode 100644 index 00000000..e59e6745 --- /dev/null +++ b/autoapi/index.html @@ -0,0 +1,484 @@ + + + + + + + + + API Reference — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

API Reference

+

This page contains auto-generated API reference documentation 1.

+
+ +
+
+
1
+

Created with sphinx-autoapi

+
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.html b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.html new file mode 100644 index 00000000..05decfab --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.html @@ -0,0 +1,203 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

CybosPlusDispatch

CybosPlusIncompleteProgID

CybosPlusEntrypoint

http://cybosplus.github.io/

+
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusDispatch(entrypoint, progid)[source]
+
+ +
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusIncompleteProgID(entrypoint, prefix)[source]
+
+ +
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint.CybosPlusEntrypoint[source]
+

Bases: koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin

+

http://cybosplus.github.io/

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.html b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.html new file mode 100644 index 00000000..d7328956 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.html @@ -0,0 +1,274 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

CybosPlusEntrypointMixin

+
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+GetConnectState(self)[source]
+
+ +
+
+classmethod ConnectUsingPywinauto_Impl(cls, credentials=None)[source]
+

https://github.com/ippoeyeslhw/cppy/blob/master/cp_luncher.py

+
+ +
+
+classmethod ConnectUsingPywinauto_RunScriptInSubprocess(cls, credentials=None)[source]
+
+ +
+
+ConnectUsingPywinauto(self, credentials=None)[source]
+
+ +
+
+Connect(self, credentials=None)[source]
+
+ +
+
+CommConnect(self, credentials=None)[source]
+
+ +
+
+EnsureConnected(self, credentials=None)[source]
+
+ +
+
+GetCodeListByMarketAsList(self, market)[source]
+

0: 구분없음 +1: 거래소 +2: 코스닥 +3: 프리보드 +4: KRX

+
+ +
+
+GetKospiCodeList(self)[source]
+
+ +
+
+GetKosdaqCodeList(self)[source]
+
+ +
+
+GetGeneralCodeList(self, include_preferred_stock=False, include_etn=False, include_etf=False, include_mutual_fund=False, include_reits=False, include_kosdaq=False)[source]
+
+ +
+
+GetStockDataAsDataFrame(self, code, chart_type, interval, start_date=None, end_date=None, adjusted_price=False, adjustement_only=False)[source]
+

http://cybosplus.github.io/cpsysdib_rtf_1_/stockchart.htm

+
+ +
+
+GetDailyStockDataAsDataFrame(self, code, start_date=None, end_date=None, adjusted_price=False)[source]
+
+ +
+
+GetMinuteStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, adjusted_price=False)[source]
+
+ +
+
+GetDailyAdjustmentRatioAsDataFrame(self, code, start_date=None, end_date=None)[source]
+
+ +
+
+GetCurrentStockDataAsDataFrame(self, codes)[source]
+

http://cybosplus.github.io/cpdib_rtf_1_/stockmst2.htm

+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.html b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.html new file mode 100644 index 00000000..b7a582ba --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.html @@ -0,0 +1,216 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.core.CybosPlusError

+
+

Module Contents

+
+
+exception koapy.backend.daishin_cybos_plus.core.CybosPlusError.CybosPlusError[source]
+

Bases: Exception

+

Common base class for all non-exit exceptions.

+
+ +
+
+exception koapy.backend.daishin_cybos_plus.core.CybosPlusError.CybosPlusRequestError(code, message=None)[source]
+

Bases: CybosPlusError

+

아래 문서에서 [BlockRequest/Blockrequest2/Request의 리턴값] 내용 참조 +http://cybosplus.github.io/cputil_rtf_1_/cybosplus_interface.htm

+
+
+ERROR_MESSAGE_BY_CODE[source]
+
+ +
+
+classmethod get_error_message_by_code(cls, code, default=None)[source]
+
+ +
+
+classmethod check_code_or_raise(cls, code)[source]
+
+ +
+
+classmethod wrap_to_check_code_or_raise(cls, func)[source]
+
+ +
+
+classmethod try_or_raise(cls, arg)[source]
+
+ +
+
+property code(self)[source]
+
+ +
+
+property message(self)[source]
+
+ +
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.html b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.html new file mode 100644 index 00000000..d36f5a8e --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

CybosPlusLookupRequestRateLimiter

시세 오브젝트 조회 제한: 15초에 최대 60건으로제한

CybosPlusTradeRequestRateLimiter

주문관련 오브젝트 조회 제한: 15초에 최대 20건으로제한

+
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter.CybosPlusLookupRequestRateLimiter[source]
+

Bases: koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter

+

시세 오브젝트 조회 제한: 15초에 최대 60건으로제한

+

Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. +http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640

+
+ +
+
+class koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter.CybosPlusTradeRequestRateLimiter[source]
+

Bases: koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter

+

주문관련 오브젝트 조회 제한: 15초에 최대 20건으로제한

+

Q. 플러스 데이터 요청 사용 제한에 대해 알고 싶습니다. +http://money2.daishin.com/e5/mboard/ptype_accordion/plusFAQ/DW_Basic_List.aspx?boardseq=298&m=9508&p=8835&v=8640

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/core/index.html b/autoapi/koapy/backend/daishin_cybos_plus/core/index.html new file mode 100644 index 00000000..5c782125 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/core/index.html @@ -0,0 +1,172 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.core — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/index.html b/autoapi/koapy/backend/daishin_cybos_plus/index.html new file mode 100644 index 00000000..c0f428e6 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/index.html @@ -0,0 +1,182 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.html new file mode 100644 index 00000000..04633643 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.html @@ -0,0 +1,211 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + +

CybosPlusDispatchProxyMethod

CybosPlusDispatchProxy

CybosPlusIncompleteProgIDProxy

CybosPlusEntrypointProxy

+
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusDispatchProxyMethod(proxy, name)[source]
+
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusDispatchProxy(proxy, progid)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusIncompleteProgIDProxy(proxy, prefix)[source]
+
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy.CybosPlusEntrypointProxy(host=None, port=None)[source]
+

Bases: koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.html new file mode 100644 index 00000000..fa91b9e6 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.html @@ -0,0 +1,204 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

CybosPlusProxyService

+
+
+

Functions

+ ++++ + + + + + +

main()

+
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService.CybosPlusProxyService(host=None, port=None, max_workers=None)[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService.main()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.html new file mode 100644 index 00000000..8dd58f4c --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

AssignPrimitive(message, value)

ExtractPrimitive(message)

Protoc()

+
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.AssignPrimitive(message, value)[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.ExtractPrimitive(message)[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils.Protoc()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.html new file mode 100644 index 00000000..302cc675 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.html @@ -0,0 +1,255 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + +

CybosPlusEvent

CybosPlusEventIterator

CybosPlusEventHandler

CybosPlusProxyServiceServicer

Missing associated documentation comment in .proto file.

+
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEvent(iterator)[source]
+
+
+done(self)[source]
+
+ +
+
+wait_for_done(self)[source]
+
+ +
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventIterator(handler)[source]
+
+
+notify(self)[source]
+
+ +
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventHandler[source]
+
+
+OnRecieved(self)[source]
+
+ +
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusProxyServiceServicer[source]
+

Bases: koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer

+

Missing associated documentation comment in .proto file.

+
+
+Dispatch(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Property(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Method(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Event(self, request_iterator, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.html new file mode 100644 index 00000000..1d4d2e4d --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.html @@ -0,0 +1,357 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2

+

Generated protocol buffer code.

+
+

Module Contents

+
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.DESCRIPTOR[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.message_type[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.DispatchRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.DispatchResponse[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.PropertyRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.PrimitiveValueArray[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.PrimitiveValue[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.PropertyResponse[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.Argument[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.MethodRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.MethodResponse[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventStartRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventDoneRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventStopRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventRequest[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventStartedResponse[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventFiredResponse[source]
+
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2.EventResponse[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.html new file mode 100644 index 00000000..c162ddfd --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.html @@ -0,0 +1,271 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc

+

Client and server classes corresponding to protobuf-defined services.

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

CybosPlusProxyServiceStub

Missing associated documentation comment in .proto file.

CybosPlusProxyServiceServicer

Missing associated documentation comment in .proto file.

CybosPlusProxyService

Missing associated documentation comment in .proto file.

+
+
+

Functions

+ ++++ + + + + + +

add_CybosPlusProxyServiceServicer_to_server(servicer, server)

+
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceStub(channel)[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+
+Dispatch(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Property(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Method(self, request, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+
+Event(self, request_iterator, context)[source]
+

Missing associated documentation comment in .proto file.

+
+ +
+ +
+
+koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.add_CybosPlusProxyServiceServicer_to_server(servicer, server)[source]
+
+ +
+
+class koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyService[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+
+static Dispatch(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static Property(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static Method(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static Event(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.html b/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.html new file mode 100644 index 00000000..5e891f45 --- /dev/null +++ b/autoapi/koapy/backend/daishin_cybos_plus/proxy/index.html @@ -0,0 +1,174 @@ + + + + + + + + + koapy.backend.daishin_cybos_plus.proxy — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/index.html b/autoapi/koapy/backend/index.html new file mode 100644 index 00000000..2c5ba367 --- /dev/null +++ b/autoapi/koapy/backend/index.html @@ -0,0 +1,258 @@ + + + + + + + + + koapy.backend — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend

+
+

Subpackages

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.html new file mode 100644 index 00000000..f1e7d3a1 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.html @@ -0,0 +1,203 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

KiwoomOpenApiPlusConditionEntry

KiwoomOpenApiPlusConditionFile

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionEntry(header, item_id, group_id, group_name, group_tp, name, group_id_small, order_no, type_position, upjong, portfolio, recommend, acc, group, excepts, month, exp, count, rules)[source]
+
+
+classmethod from_datfile(cls, f: TextIO)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionFile(version: str, entries: Sequence[KiwoomOpenApiPlusConditionEntry])[source]
+
+
+classmethod from_datfile(cls, f: Union[str, os.PathLike, TextIO], encoding: Optional[str] = None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.html new file mode 100644 index 00000000..2f892a46 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.html @@ -0,0 +1,1694 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusDispatchFunctions

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions[source]
+
+
+CommConnect(self) → int[source]
+

로그인 윈도우를 실행한다.

+

수동 로그인 설정인 경우 로그인창을 출력. +자동 로그인 설정인 경우 로그인창에서 자동으로 로그인을 시도합니다.

+

로그인이 성공하거나 실패하는 경우 OnEventConnect() 이벤트가 발생하고 이벤트의 +인자 값으로 로그인 성공 여부를 알 수 있다.

+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+CommTerminate(self) → None[source]
+

더 이상 지원하지 않는 함수.

+

프로그램 종료없이 서버와의 접속만 단절시키는 함수입니다. +※ 함수 사용 후 사용자의 오해소지가 생기는 이유로 더 이상 사용할 수 없는 함수입니다.

+

통신 연결 상태는 GetConnectState() 메소드로 알 수 있다.

+
+ +
+
+CommRqData(self, sRQName: str, sTrCode: str, nPrevNext: int, sScreenNo: str) → int[source]
+

통신 데이터를 서버로 전송한다.

+
+
반환 코드 구분:
    +
  • OP_ERR_NONE(0): 정상처리

  • +
  • OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가

  • +
  • OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패

  • +
  • OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패

  • +
+
+
+
+
Parameters
+
    +
  • sRQName (str) – 사용자 구분명 (임의로 지정, 한글 지원)

  • +
  • sTrCode (str) – 조회하려는 TR 코드

  • +
  • nPrevNext (int) – 연속조회 여부 (0:조회, 2:연속)

  • +
  • sScreenNo (str) – 화면번호 (4자리 숫자 임의로 지정)

  • +
+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+GetLoginInfo(self, sTag: str) → str[source]
+

로그인한 사용자 정보를 반환한다.

+
+
태그값 구분:
    +
  • “ACCOUNT_CNT”: 전체 보유계좌 개수를 반환합니다.

  • +
  • “ACCLIST” 또는 “ACCNO”: 구분자 ‘;’ 로 연결된 전체 보유계좌 목록을 반환합니다.

  • +
  • “USER_ID”: 사용자 ID를 반환합니다.

  • +
  • “USER_NAME”: 사용자 이름을 반환합니다.

  • +
  • “KEY_BSECGB”: 키보드 보안 해지 여부를 반환합니다. (0:정상, 1:해지)

  • +
  • “FIREW_SECGB”: 방화벽 설정 여부를 반환합니다. (0:미설정, 1:설정, 2:해지)

  • +
  • “GetServerGubun”: 접속서버 구분을 반환합니다. (1:모의투자, 나머지:실거래서버)

  • +
+
+
+
+
Parameters
+

sTag (str) – 사용자 정보 구분 태그 값

+
+
Returns
+

태그값에 따른 데이터 반환

+
+
Return type
+

str

+
+
+
+ +
+
+SendOrder(self, sRQName: str, sScreenNo: str, sAccNo: str, nOrderType: int, sCode: str, nQty: int, nPrice: int, sHogaGb: str, sOrgOrderNo: str) → int[source]
+

주식 주문을 서버로 전송한다.

+

서버에 주문을 전송하는 함수 입니다. +9개 인자값을 가진 주식주문 함수이며 리턴값이 0이면 성공이며 나머지는 에러입니다. +1초에 5회만 주문가능하며 그 이상 주문요청하면 에러 -308을 리턴합니다.

+

※ 시장가, 최유리지정가, 최우선지정가, 시장가IOC, 최유리IOC, 시장가FOK, 최유리FOK, 장전시간외, 장후시간외 주문시 주문가격은 0으로 입력합니다. +※ 취소 주문일때 주문가격은 0으로 입력합니다.

+
+
거래 구분:
    +
  • 00: 지정가

  • +
  • 03: 시장가

  • +
  • 05: 조건부지정가

  • +
  • 06: 최유리지정가

  • +
  • 07: 최우선지정가

  • +
  • 10: 지정가IOC

  • +
  • 13: 시장가IOC

  • +
  • 16: 최유리IOC

  • +
  • 20: 지정가FOK

  • +
  • 23: 시장가FOK

  • +
  • 26: 최유리FOK

  • +
  • 61: 장전시간외종가

  • +
  • 62: 시간외단일가매매

  • +
  • 81: 장후시간외종가

  • +
+
+
+

※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다.

+
+
정규장 외 주문:
    +
  • +
    장전 동시호가 주문
      +
    • 08:30 ~ 09:00. 거래구분 00:지정가/03:시장가 (일반주문처럼)

    • +
    • ※ 08:20 ~ 08:30 시간의 주문은 키움에서 대기하여 08:30 에 순서대로 거래소로 전송합니다.

    • +
    +
    +
    +
  • +
  • +
    장전시간외 종가
      +
    • 08:30 ~ 08:40. 거래구분 61:장전시간외종가. 가격 0입력

    • +
    • ※ 전일 종가로 거래. 미체결시 자동취소되지 않음

    • +
    +
    +
    +
  • +
  • +
    장마감 동시호가 주문
      +
    • 15:20 ~ 15:30. 거래구분 00:지정가/03:시장가 (일반주문처럼)

    • +
    +
    +
    +
  • +
  • +
    장후 시간외 종가
      +
    • 15:40 ~ 16:00. 거래구분 81:장후시간외종가. 가격 0입력

    • +
    • ※ 당일 종가로 거래

    • +
    +
    +
    +
  • +
  • +
    시간외 단일가
      +
    • 16:00 ~ 18:00. 거래구분 62:시간외단일가. 가격 입력

    • +
    • ※ 10분 단위로 체결, 당일 종가대비 +-10% 가격으로 거래

    • +
    +
    +
    +
  • +
+
+
주문 유형:
    +
  • 1: 신규매수

  • +
  • 2: 신규매도

  • +
  • 3: 매수취소

  • +
  • 4: 매도취소

  • +
  • 5: 매수정정

  • +
  • 6: 매도정정

  • +
+
+
+
+
Parameters
+
    +
  • sRQName (str) – 사용자 구분 요청명

  • +
  • sScreenNo (str) – 화면번호 (4자리)

  • +
  • sAccNo (str) – 계좌번호 (10자리)

  • +
  • nOrderType (int) – 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정)

  • +
  • sCode (str) – 종목코드 (6자리)

  • +
  • nQty (int) – 주문수량

  • +
  • nPrice (int) – 주문단가

  • +
  • sHogaGb (str) – 거래구분 (혹은 호가구분)

  • +
  • sOrgOrderNo (str) – 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다.

  • +
+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+SendOrderFO(self, sRQName: str, sScreenNo: str, sAccNo: str, sCode: str, lOrdKind: int, sSlbyTp: str, sOrdTp: str, lQty: int, sPrice: str, sOrgOrdNo: str) → int[source]
+

선물/옵션 주문을 서버로 전송한다.

+

서버에 주문을 전송하는 함수 입니다. +코스피지수200 선물옵션 전용 주문함수입니다.

+
+
거래 구분:
    +
  • 1: 지정가

  • +
  • 2: 조건부지정가

  • +
  • 3: 시장가

  • +
  • 4: 최유리지정가

  • +
  • 5: 지정가(IOC)

  • +
  • 6: 지정가(FOK)

  • +
  • 7: 시장가(IOC)

  • +
  • 8: 시장가(FOK)

  • +
  • 9: 최유리지정가(IOC)

  • +
  • A: 최유리지정가(FOK)

  • +
+
+
+

※ 장종료 후 시간외 주문은 지정가 선택

+
+
Parameters
+
    +
  • sRQName (str) – 사용자 구분명

  • +
  • sScreenNo (str) – 화면번호

  • +
  • sAccNo (str) – 계좌번호 (10자리)

  • +
  • sCode (str) – 종목코드

  • +
  • lOrdKind (int) – 주문종류 (1:신규매매, 2:정정, 3:취소)

  • +
  • sSlbyTp (str) – 매매구분 (1:매도, 2:매수)

  • +
  • sOrdTp (str) – 거래구분

  • +
  • lQty (int) – 주문수량

  • +
  • sPrice (str) – 주문가격

  • +
  • sOrgOrdNo (str) – 원주문번호

  • +
+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+SetInputValue(self, sID: str, sValue: str) → None[source]
+

TR 입력 값을 서버통신 전에 입력한다.

+

조회요청시 TR의 Input값을 지정하는 함수입니다. +CommRqData() 호출 전에 입력값들을 셋팅합니다. +각 TR마다 Input 항목이 다릅니다. 순서에 맞게 Input 값들을 셋팅해야 합니다.

+
+
Parameters
+
    +
  • sID (str) – TR에 명시된 Input 이름

  • +
  • sValue (str) – Input 이름으로 지정한 값

  • +
+
+
+
+ +
+
+SetOutputFID(self, sID: str) → int[source]
+

1.0.0.1 버전 이후 사용하지 않음.

+
+ +
+
+CommGetData(self, sJongmokCode: str, sRealType: str, sFieldName: str, nIndex: int, sInnerFieldName: str) → str[source]
+

이 함수는 지원하지 않을 것이므로 용도에 맞는 전용 함수를 사용할 것. (비고참고)

+

일부 TR에서 사용상 제약이 있으므로 이 함수 대신 GetCommData() 함수를 사용하시기 바랍니다.

+
+
비고:
    +
  • 조회 정보 요청: GetCommData(strTrCode: str, strRecordName: str, nIndex: int, strItemName: str)

  • +
  • 실시간 정보 요청: GetCommRealData(sTrCode: str, nFid: int)

  • +
  • 체결 정보 요청: GetChejanData(nFid: int)

  • +
+
+
+
+ +
+
+DisconnectRealData(self, sScnNo: str) → None[source]
+

화면 내 모든 리얼데이터 요청을 제거한다.

+

시세데이터를 요청할때 사용된 화면번호를 이용하여 +해당 화면번호로 등록되어져 있는 종목의 실시간시세를 서버에 등록해지 요청합니다. +이후 해당 종목의 실시간시세는 수신되지 않습니다. +단, 해당 종목이 또다른 화면번호로 실시간 등록되어 있는 경우 해당종목에대한 실시간시세 데이터는 계속 수신됩니다.

+

화면을 종료할 때 반드시 위 함수를 호출해야 한다.

+
+
Parameters
+

sScnNo – 화면번호 (4자리)

+
+
+
+ +
+
+GetRepeatCnt(self, sTrCode: str, sRecordName: str) → int[source]
+

레코드 반복횟수를 반환한다.

+

데이터 수신시 멀티데이터의 갯수(반복수)를 얻을수 있습니다. +예를 들어 차트조회는 한번에 최대 900개 데이터를 수신할 수 있는데 +이렇게 수신한 데이터갯수를 얻을때 사용합니다. +이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다.

+
+
Parameters
+
    +
  • sTrCode (str) – TR 이름

  • +
  • sRecordName (str) – 레코드 이름

  • +
+
+
Returns
+

레코드의 반복횟수

+
+
Return type
+

int

+
+
+
+ +
+
+CommKwRqData(self, sArrCode: str, bNext: int, nCodeCount: int, nTypeFlag: int, sRQName: str, sScreenNo: str) → int[source]
+

복수종목조회 요청을 서버로 송신한다.

+

한번에 100종목까지 조회할 수 있는 복수종목 조회함수 입니다. +함수인자로 사용하는 종목코드 리스트는 조회하려는 종목코드 사이에 구분자 ‘;’ 를 추가해서 만들면 됩니다. +수신되는 데이터는 TR목록에서 복수종목정보요청(OPTKWFID) Output을 참고하시면 됩니다.

+

※ OPTKWFID TR은 CommKwRqData() 함수 전용으로, CommRqData 로는 사용할 수 없습니다. +※ OPTKWFID TR은 영웅문4 HTS의 관심종목과는 무관합니다.

+
+
반환 코드 구분:
    +
  • OP_ERR_NONE(0): 정상처리

  • +
  • OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가

  • +
  • OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패

  • +
  • OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패

  • +
+
+
+
+
Parameters
+
    +
  • sArrCode (str) – 종목리스트

  • +
  • bNext (int) – 연속조회 여부 (0:기본값, 1:연속조회(지원안함))

  • +
  • nCodeCount (int) – 종목개수

  • +
  • nTypeFlag (int) – 조회구분 (0:주식 종목, 3:선물옵션 종목)

  • +
  • sRQName (str) – 사용자 구분명

  • +
  • sScreenNo (str) – 화면번호 (4자리)

  • +
+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+GetAPIModulePath(self) → str[source]
+

OpenAPI 모듈의 경로를 반환한다.

+
+
Returns
+

OpenAPI 모듈의 설치 경로

+
+
Return type
+

str

+
+
+
+ +
+
+GetCodeListByMarket(self, sMarket: str) → str[source]
+

시장구분에 따른 종목코드를 반환한다.

+

주식 시장별 종목코드 리스트를 ‘;’ 로 구분해서 전달합니다. +시장구분값을 “” 공백으로 하면 전체시장 코드리스트를 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
시장 구분:
    +
  • 0: 장내

  • +
  • 3: ELW

  • +
  • 4: 뮤추얼펀드

  • +
  • 5: 신주인수권

  • +
  • 6: 리츠

  • +
  • 8: ETF

  • +
  • 9: 하이일드펀드

  • +
  • 10: 코스닥

  • +
  • 30: K-OTC

  • +
  • 50: 코넥스 (KONEX)

  • +
+
+
+
+
Parameters
+

sMarket (str) – 시장 구분값

+
+
Returns
+

종목코드 리스트, 종목간 구분은 ‘;’ 이다.

+
+
Return type
+

str

+
+
+
+ +
+
+GetConnectState(self) → int[source]
+

현재 접속상태를 반환한다.

+

서버와 현재 접속 상태를 알려줍니다.

+
+
Returns
+

접속상태, 1:연결, 0:연결안됨

+
+
Return type
+

int

+
+
+
+ +
+
+GetMasterCodeName(self, sTrCode: str) → str[source]
+

종목코드의 한글명을 반환한다.

+

종목코드에 해당하는 종목명을 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+

장내외, 지수선옵, 주식선옵 검색 가능.

+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

종목 한글명

+
+
Return type
+

str

+
+
+
+ +
+
+GetMasterListedStockCnt(self, sTrCode: str) → int[source]
+

종목코드의 상장주식수를 반환한다.

+

입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

상장주식수

+
+
Return type
+

int

+
+
+
+ +
+
+GetMasterConstruction(self, sTrCode: str) → str[source]
+

종목코드의 감리구분을 반환한다.

+

입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. +(정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목)

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
감리 구분:
    +
  • 정상

  • +
  • 투자주의

  • +
  • 투자경고

  • +
  • 투자위험

  • +
  • 투자주의환기종목

  • +
+
+
+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

감리구분 (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목)

+
+
Return type
+

str

+
+
+
+ +
+
+GetMasterListedStockDate(self, sTrCode: str) → str[source]
+

종목코드의 상장일을 반환한다.

+

입력한 종목의 상장일을 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

상장일 (8자리, YYYYMMDD)

+
+
Return type
+

str

+
+
+
+ +
+
+GetMasterLastPrice(self, sTrCode: str) → str[source]
+

종목코드의 전일가를 반환한다.

+

입력한 종목의 당일 기준가를 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

전일가

+
+
Return type
+

str

+
+
+
+ +
+
+GetMasterStockState(self, sTrCode: str) → str[source]
+

종목코드의 종목상태를 반환한다.

+

입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
Parameters
+

sTrCode (str) – 종목코드 (4자리)

+
+
Returns
+

종목상태 (정상, 증거금N%, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능)

+
+
Return type
+

str

+
+
+
+ +
+
+GetDataCount(self, strRecordName: str) → int[source]
+

레코드의 반복개수를 반환한다.

+

※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 +해당 함수 대신 GetRepeatCnt() 를 사용하는게 더 바람직할 듯

+
+
Parameters
+

strRecordName (str) – 레코드 명

+
+
Returns
+

레코드 반복개수

+
+
Return type
+

str

+
+
+
+ +
+
+GetOutputValue(self, strRecordName: str, nRepeatIdx: int, nItemIdx: int) → str[source]
+

레코드의 반복순서와 아이템의 출력순서에 따라 수신데이터를 반환한다.

+

※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 +해당 함수 대신 GetCommData() 를 사용하는게 더 바람직할 듯

+
+
Parameters
+
    +
  • strRecordName (str) – 레코드 명

  • +
  • nRepeatIdx (int) – 반복 순서

  • +
  • nItemIdx (int) – 아이템 순서

  • +
+
+
Returns
+

수신 데이터

+
+
Return type
+

str

+
+
+
+ +
+
+GetCommData(self, strTrCode: str, strRecordName: str, nIndex: int, strItemName: str) → str[source]
+

수신 데이터를 반환한다.

+

OnReceiveTRData() 이벤트가 발생될때 수신한 데이터를 얻어오는 함수입니다. +이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다.

+
+
Parameters
+
    +
  • strTrCode (str) – TR코드

  • +
  • strRecordName (str) – 레코드명

  • +
  • nIndex (int) – 복수데이터 인덱스

  • +
  • strItemName (str) – 아이템명 (TR별 출력항목 이름)

  • +
+
+
Returns
+

수신 데이터

+
+
Return type
+

str

+
+
+
+ +
+
+GetCommRealData(self, sTrCode: str, nFid: int) → str[source]
+

실시간 시세 데이터를 반환한다.

+

실시간시세 데이터 수신 이벤트인 OnReceiveRealData() 가 발생될때 실시간데이터를 얻어오는 함수입니다. +이 함수는 OnReceiveRealData() 이벤트가 발생될때 그 안에서 사용해야 합니다. +FID 값은 KOAStudio 의 “실시간목록” 탭에서 확인할 수 있습니다.

+

일반적으로 strTrCode 는 OnReceiveRealData() 이벤트 함수의 첫번째 매개변수를 사용한다.

+
+
Parameters
+
    +
  • strTrCode (str) – TR코드

  • +
  • nFid (int) – 실시간 아이템

  • +
+
+
Returns
+

수신 데이터

+
+
Return type
+

str

+
+
+
+ +
+
+GetChejanData(self, nFid: int) → str[source]
+

체결잔고 데이터를 반환한다.

+

OnReceiveChejan() 이벤트가 발생될때 FID 에 해당되는 값을 구하는 함수입니다. +이 함수는 OnReceiveChejan() 이벤트 안에서 사용해야 합니다. +Ex) 체결가 = GetChejanData(910)

+
+
Parameters
+

nFid (int) – 체결잔고 아이템

+
+
Returns
+

수신 데이터

+
+
Return type
+

str

+
+
+
+ +
+
+GetThemeGroupList(self, nType: int) → str[source]
+

테마코드와 테마명을 반환한다.

+

반환값의 코드와 코드명 구분은 ‘|’, 코드의 구분은 ‘;’ +Ex) 100|태양광_폴리실리콘;152|합성섬유

+
+
Parameters
+

nType (int) – 정렬순서 (0:코드순, 1:테마순)

+
+
Returns
+

코드와 코드명 리스트

+
+
Return type
+

str

+
+
+
+ +
+
+GetThemeGroupCode(self, strThemeCode: str) → str[source]
+

테마코드에 소속된 종목코드를 반환한다.

+

반환값의 종목코드간 구분은 ‘;’ +Ex) A000660;A005930

+
+
Parameters
+

strThemeCode (str) – 테마코드

+
+
Returns
+

종목코드 리스트

+
+
Return type
+

str

+
+
+
+ +
+
+GetFutureList(self) → str[source]
+

지수선물 리스트를 반환한다.

+

지수선물 종목코드 리스트를 ‘;’로 구분해서 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+

반환값의 종목코드간 구분은 ‘;’ +Ex) 101J9000;101JC000

+
+
Returns
+

종목코드 리스트

+
+
Return type
+

str

+
+
+
+ +
+
+GetFutureCodeByIndex(self, nIndex: int) → str[source]
+

지수선물 코드를 반환한다.

+
+
Ex) 최근월선물 = GetFutureCodeByIndex(0)

최근월스프레드 = GetFutureCodeByIndex(4)

+
+
+
+
Parameters
+

nIndex (int) – 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드

+
+
Returns
+

종목코드

+
+
Return type
+

str

+
+
+
+ +
+
+GetActPriceList(self) → str[source]
+

지수옵션 행사가 리스트를 반환한다.

+

지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ‘;’ 로 구분해서 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+

※ PDF 문서상의 예시에서는 소수점 아래가 존재하는 예시지만, KOAStudio 의 설명과 예시에서는 그렇지 않음. +아마도 KOAStudio 의 설명을 따르는게 더 바람직할 듯.

+
+
Returns
+

행사가

+
+
Return type
+

str

+
+
+
+ +
+
+GetMonthList(self) → str[source]
+

지수옵션 월물 리스트를 반환한다.

+

지수옵션 월물정보를 ‘;’ 로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+

반환값의 월물간 구분은 ‘;’ +Ex) 201412;201409;201408;201407;201407;201408;201409;201412

+
+
Returns
+

월물 (YYYYMM;YYYYMM;…)

+
+
Return type
+

str

+
+
+
+ +
+
+GetOptionCode(self, strActPrice: str, nCp: int, strMonth: str) → str[source]
+

행사가와 월물 콜풋으로 종목코드를 구한다.

+

인자로 지정한 지수옵션 코드를 전달합니다.

+

로그인 한 후에 사용할 수 있는 함수입니다.

+
+
Parameters
+
    +
  • strActPrice (str) – 행사가 (소수점 포함)

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • strMonth (str) – 월물 (6자리, YYYYMM)

  • +
+
+
Returns
+

종목코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetOptionCode("260.00", 2, "201407")
+
+
+
+ +
+
+GetOptionCodeByMonth(self, sTrCode: str, nCp: int, strMonth: str) → str[source]
+

입력된 종목코드와 동일한 행사가의 코드중 입력한 월물의 코드를 구한다.

+
+
Parameters
+
    +
  • sTrCode (str) – 종목코드

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • strMonth (str) – 월물 (6자리, YYYYMM)

  • +
+
+
Returns
+

종목코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetOptionCodeByMonth("201J7260", 2, "201412")
+"201JC260"
+
+
+
+ +
+
+GetOptionCodeByActPrice(self, sTrCode: str, nCp: int, nTick: int) → str[source]
+

입력된 종목코드와 동일한 월물의 코드중 입력한 틱만큼 벌어진 코드를 구한다.

+
+
Parameters
+
    +
  • sTrCode (str) – 종목코드

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • nTick (int) – 행사가 틱

  • +
+
+
Returns
+

종목코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetOptionCodeByActPrice("201J7260", 2, -1)
+"201J7262"
+
+
+
+ +
+
+GetSFutureList(self, strBaseAssetCode: str) → str[source]
+

주식선물 코드 리스트를 반환한다.

+

출력값의 코드간 구분은 ‘;’ 이다.

+
+
Parameters
+

strBaseAssetCode (str) – 기초자산코드

+
+
Returns
+

종목코드 리스트

+
+
Return type
+

str

+
+
+
+ +
+
+GetSFutureCodeByIndex(self, strBaseAssetCode: str, nIndex: int) → str[source]
+

주식선물 코드를 반환한다.

+
+
Parameters
+
    +
  • strBaseAssetCode (str) – 기초자산코드

  • +
  • nIndex (int) – 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드, 8 ~ 11: 스타 선물, 12 ~ : 스타 스프레드

  • +
+
+
Returns
+

종목코드 리스트

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSFutureCodeByIndex("11", 0)
+
+
+
+ +
+
+GetSActPriceList(self, strBaseAssetGb: str) → str[source]
+

주식옵션 행사가 리스트를 반환한다.

+
+
Parameters
+

strBaseAssetGb (str) – 기초자산코드구분

+
+
Returns
+

행사가 리스트, 행사가간 구분은 ‘;’

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSActPriceList("11")
+
+
+
+ +
+
+GetSMonthList(self, strBaseAssetGb: str) → str[source]
+

주식옵션 월물 리스트를 반환한다.

+
+
Parameters
+

strBaseAssetGb (str) – 기초자산코드구분

+
+
Returns
+

월물 리스트, 월물간 구분은 ‘;’

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSMonthList("11")
+
+
+
+ +
+
+GetSOptionCode(self, strBaseAssetGb: str, strActPrice: str, nCp: int, strMonth: str) → str[source]
+

주식옵션 코드를 반환한다.

+
+
Parameters
+
    +
  • strBaseAssetGb (str) – 기초자산코드구분

  • +
  • strActPrice (str) – 행사가 (소수점 포함)

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • strMonth (str) – 월물 (6자리, YYYYMM)

  • +
+
+
Returns
+

주식옵션 코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSOptionCode("11", "1300000", 2, "1412")
+
+
+
+ +
+
+GetSOptionCodeByMonth(self, strBaseAssetGb: str, sTrCode: str, nCp: int, strMonth: str) → str[source]
+

입력한 주식옵션 코드에서 월물만 변경하여 반환한다.

+
+
Parameters
+
    +
  • strBaseAssetGb (str) – 기초자산코드구분

  • +
  • sTrCode (str) – 종목코드

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • strMonth (str) – 월물 (6자리, YYYYMM)

  • +
+
+
Returns
+

주식옵션 코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSOptionCodeByMonth("11", "211J8045", 2, "1412")
+
+
+
+ +
+
+GetSOptionCodeByActPrice(self, strBaseAssetGb: str, sTrCode: str, nCp: int, nTick: int) → str[source]
+

입력한 주식옵션 코드에서 행사가만 변경하여 반환한다.

+
+
Parameters
+
    +
  • strBaseAssetGb (str) – 기초자산코드구분

  • +
  • sTrCode (str) – 종목코드

  • +
  • nCp (int) – 콜/풋 구분 (2:콜, 3:풋)

  • +
  • nTick (int) – 행사가 틱

  • +
+
+
Returns
+

주식옵션 코드

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetSOptionCodeByActPrice("11", "211J8045", 2, 4);
+
+
+
+ +
+
+GetSFOBasisAssetList(self) → str[source]
+

주식선옵 기초자산코드/종목명을 반환한다.

+
+
Returns
+

기초자산코드/종목명, 코드와 종목명 구분은 ‘|’, 코드간 구분은 ‘;’

+
+
Return type
+

str

+
+
+
+ +
+
+GetOptionATM(self) → str[source]
+

지수옵션 ATM을 반환한다.

+
+
Returns
+

ATM

+
+
Return type
+

str

+
+
+
+ +
+
+GetSOptionATM(self, strBaseAssetGb: str) → str[source]
+

주식옵션 ATM을 반환한다.

+
+
Returns
+

ATM

+
+
Return type
+

str

+
+
+
+ +
+
+GetBranchCodeName(self) → str[source]
+

회원사 코드와 이름을 반환합니다.

+
+
Returns
+

회원사코드/회원사명, 코드와 이름 구분은 ‘|’, 코드간 구분은 ‘;’ (회원사코드|회원사명;회원사코드|회원사명;…)

+
+
Return type
+

str

+
+
+
+ +
+
+CommInvestRqData(self, sMarketGb: str, sRQName: str, sScreenNo: str) → int[source]
+

지원하지 않는 함수.

+
+
시장 구분:
    +
  • 001: 코스피

  • +
  • 002: 코스닥

  • +
  • 003: 선물

  • +
  • 004: 콜옵션

  • +
  • 005: 풋옵션

  • +
  • 006: 스타선물

  • +
  • 007: 주식선물

  • +
  • 008: 3년국채

  • +
  • 009: 5년국채

  • +
  • 010: 10년국채

  • +
  • 011: 달러선물

  • +
  • 012: 엔선물

  • +
  • 013: 유로선물

  • +
  • 014: 미니금선물

  • +
  • 015: 금선물

  • +
  • 016: 돈육선물

  • +
  • 017: 달러콜옵션

  • +
  • 018: 달러풋옵션

  • +
+
+
+
+
Parameters
+
    +
  • sMarketGb (str) – 시장구분

  • +
  • sRQName (str) – 사용자 구분값

  • +
  • sScreenNo (str) – 화면번호 (4자리)

  • +
+
+
Returns
+

통신결과

+
+
Return type
+

str

+
+
+

Examples

+
>>> CommInvestRqData("T00108;T00109", 0, 2, "RQ_1", "0101")
+
+
+
+ +
+
+SendOrderCredit(self, sRQName: str, sScreenNo: str, sAccNo: str, nOrderType: int, sCode: str, nQty: int, nPrice: int, sHogaGb: str, sCreditGb: str, sLoanDate: str, sOrgOrderNo: str) → int[source]
+

신용주식 주문을 서버로 전송한다.

+

서버에 주문을 전송하는 함수 입니다. +국내주식 신용주문 전용함수입니다. 대주거래는 지원하지 않습니다.

+
+
거래 구분:
    +
  • 00: 지정가

  • +
  • 03: 시장가

  • +
  • 05: 조건부지정가

  • +
  • 06: 최유리지정가

  • +
  • 07: 최우선지정가

  • +
  • 10: 지정가IOC

  • +
  • 13: 시장가IOC

  • +
  • 16: 최유리IOC

  • +
  • 20: 지정가FOK

  • +
  • 23: 시장가FOK

  • +
  • 26: 최유리FOK

  • +
  • 61: 장전시간외종가

  • +
  • 62: 시간외단일가매매

  • +
  • 81: 장후시간외종가

  • +
+
+
+

※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다.

+
+
신용거래 구분:
    +
  • +
    03: 신용매수 주문 - 자기융자
      +
    • 대출일은 공백 입력

    • +
    +
    +
    +
  • +
  • +
    33: 신용매도 융자상환 주문 - 자기융자
      +
    • 대출일은 종목별 대출일 입력

    • +
    • OPW00005/OPW00004 TR조회로 대출일 조회

    • +
    +
    +
    +
  • +
  • +
    99: 신용매도 자기융자 합
      +
    • 대출일은 “99991231” 입력

    • +
    • 단, 신용잔고 5개 까지만 융자합 주문 가능

    • +
    +
    +
    +
  • +
+
+
+

대출일은 YYYYMMDD 형식입니다. +신용매도 - 자기융자 일때는 종목별 대출일을 입력하고 신용매도 - 융자합이면 “99991231”을 입력합니다.

+
+
Parameters
+
    +
  • sRQName (str) – 사용자 구분 요청명

  • +
  • sScreenNo (str) – 화면번호 (4자리)

  • +
  • sAccNo (str) – 계좌번호 (10자리)

  • +
  • nOrderType (int) – 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정)

  • +
  • sCode (str) – 종목코드 (6자리)

  • +
  • nQty (int) – 주문수량

  • +
  • nPrice (int) – 주문단가

  • +
  • sHogaGb (str) – 거래구분

  • +
  • sCreditGb (str) – 신용구분

  • +
  • sLoanDate (str) – 대출일 (8자리, YYYYMMDD)

  • +
  • sOrgOrderNo (str) – 원주문번호

  • +
+
+
Returns
+

에러코드, 성공하면 0 을, 실패하면 음수를 반환

+
+
Return type
+

int

+
+
+
+ +
+
+KOA_Functions(self, sFunctionName: str, sParam: str) → str[source]
+

OpenAPI 기본 기능 이외의 기능들을 제공하는 헬퍼 함수.

+

KOA_Function() 함수는 OpenAPI 기본 기능 이외의 기능을 사용하기 쉽도록 만든 함수입니다. +두 개의 인자값을 사용합니다.

+

기능 목록:

+
+
    +
  1. 계좌 비밀번호 입력창 출력

  2. +
+
>>> KOA_Functions("ShowAccountWindow", "")
+
+
+
    +
  1. 접속 서버 확인 (1:모의투자, 나머지:실서버)

  2. +
+
>>> KOA_Functions("GetServerGubun", "")
+
+
+

3. 주식종목 시장구분, 종목분류등 정보제공 (구분자는 ‘|’ 와 ‘;’) +호출결과는 입력한 종목에 대한 대분류, 중분류, 업종구분값을 구분자로 연결한 문자열입니다.

+
>>> KOA_Functions("GetMasterStockInfo", "039490")
+"시장구분0|거래소;시장구분1|중형주;업종구분|금융업;"
+
+
+

4. 조건검색 종목코드와 현재가 수신 (실시간 조건검색은 사용할 수 없음) +조건검색결과에 종목코드와 그 종목의 현재가를 함께 수신하는 방법이며 실시간 조건검색에서는 사용할 수 없고 오직 조건검색에만 사용할수 있습니다.

+
>>> KOA_Functions("SetConditionSearchFlag", "AddPrice") # 현재가 포함하도록 설정
+
+
+

현재가 포함으로 설정시 OnReceiveTrCondition() 이벤트에 “종목코드1^현재가1;종목코드2^현재가2;…종목코드n^현재가n” 형식으로 전달됨.

+
>>> KOA_Functions("SetConditionSearchFlag", "DelPrice") # 현재가 미포함 (원래 상태로 전환)
+
+
+

현재가 미포함시 기존처럼 “종목코드1^종목코드2…종목코드n” 형식으로 전달므로 설정에 따라 수신데이터 처리방법이 달라져야 하므로 주의하셔야 합니다.

+
    +
  1. 업종코드목록 획득

  2. +
+
>>> KOA_Functions("GetUpjongCode", "0")
+
+
+

두번째 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. +0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100

+

함수반환값은 “시장구분값,업종코드,업종명|시장구분값,업종코드,업종명|…|시장구분값,업종코드,업종명” 형식입니다. +즉 하나의 업종코드는 입력한 시장구분값과 업종코드 그리고 그 업종명이 쉼표(,)로 구분되며 각 업종코드는 ‘|’로 구분됩니다.

+
    +
  1. 업종이름 획득

  2. +
+
>>> KOA_Functions("GetUpjongNameByCode", "업종코드입력")
+
+
+

7. ETF 투자유의 종목 여부 (2020/09/17 적용) +거래소 제도개선으로 ETF/ETN 종목 중 투자유의 종목을 매수주문하는 경우 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. +(경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) +주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다.

+
>>> KOA_Functions("IsOrderWarningETF", "종목코드(6자리)")
+
+
+

투자유의 종목인 경우 “1” 값이 리턴, 그렇지 않은 경우 “0” 값 리턴. (ETF가 아닌 종목을 입력시 “0” 값 리턴.)

+

8. 주식 전종목대상 투자유의 종목 여부 (2020/11/26 적용) +거래소 제도개선으로 주식 종목 중 정리매매/단기과열/투자위험/투자경고 종목을 매수주문하는 경우 +경고 메세지 창이 출력되도록 기능이 추가 되었습니다. (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) +주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다.

+
>>> KOA_Functions("IsOrderWarningStock", "종목코드(6자리)")
+
+
+

리턴 값 - “0”:해당없음, “2”:정리매매, “3”:단기과열, “4”:투자위험, “5”:투자경고

+

9. 상장주식수 구하기 (2021/04/08 적용) +상장주식수를 구하는 GetMasterListedStockCnt() 기존 함수 사용시 특정 종목 데이터가 long 형을 Overflow 하는 현상이 있습니다. +이에, 상장주식수를 구하는 기능을 신규 추가 합니다. 사용법은 아래와 같습니다.

+
>>> KOA_Functions("GetMasterListedStockCntEx", "종목코드(6자리)")
+
+
+
+
+
Parameters
+
    +
  • sFunctionName (str) – 함수이름 혹은 기능이름

  • +
  • sParam (str) – 함수 매개변수

  • +
+
+
Returns
+

결과 데이터

+
+
Return type
+

str

+
+
+
+ +
+
+SetInfoData(self, sInfoData: str) → int[source]
+

다수의 아이디로 자동로그인이 필요할 때 사용한다.

+
+
Parameters
+

sInfoData (str) – 아이디

+
+
Returns
+

통신결과

+
+
Return type
+

int

+
+
+

Examples

+
>>> SetInfoData("UserID")
+
+
+
+ +
+
+SetRealReg(self, strScreenNo: str, strCodeList: str, strFidList: str, strOptType: str) → int[source]
+

실시간 등록을 한다.

+

종목코드와 FID 리스트를 이용해서 실시간 시세를 등록하는 함수입니다. +한번에 등록가능한 종목과 FID갯수는 100종목, 100개 입니다. +실시간 등록타입을 0으로 설정하면 등록한 종목들은 실시간 해지되고 등록한 종목만 실시간 시세가 등록됩니다. +실시간 등록타입을 1로 설정하면 먼저 등록한 종목들과 함께 실시간 시세가 등록됩니다

+

strOptType 이 “0” 으로 하면 같은 화면에서 다른 종목 코드로 실시간 등록을 하게 되면 +마지막에 사용한 종목코드만 실시간 등록이 되고 기존에 있던 종목은 실시간이 자동 해지됨. +“1” 로 하면 같은 화면에서 다른 종목들을 추가하게 되면 기존에 등록한 종목도 함께 실시간 시세를 받을 수 있음. +꼭 같은 화면이여야 하고 최초 실시간 등록은 “0” 으로 하고 이후부터 “1” 로 등록해야함.

+
+
Parameters
+
    +
  • strScreenNo (str) – 화면번호 (4자리)

  • +
  • strCodeList (str) – 종목코드 (복수종목가능, ‘;’ 구분자)

  • +
  • strFidList (str) – FID (‘;’ 구분자)

  • +
  • strOptType (str) – 등록타입 (0:최초 등록시, 혹은 기존 등록된 종목 해지하고 등록 1:기존 등록된 종목 유지하고 등록)

  • +
+
+
Returns
+

통신결과

+
+
Return type
+

int

+
+
+
+ +
+
+GetConditionLoad(self) → int[source]
+

서버에 저장된 사용자 조건식을 조회해서 임시로 파일에 저장.

+

서버에 저장된 사용자 조건검색 목록을 요청합니다. +조건검색 목록을 모두 수신하면 OnReceiveConditionVer() 이벤트가 발생됩니다. +조건검색 목록 요청을 성공하면 1, 아니면 0을 리턴합니다.

+

System 폴더에 아이디_NewSaveIndex.dat 파일로 저장된다. OCX 가 종료되면 삭제시킨다. +조건검색 사용시 이 함수를 최소 한번은 호출해야 조건검색을 할 수 있다. +영웅문에서 사용자 조건을 수정 및 추가하였을 경우에도 최신의 사용자 조건을 받고 싶으면 다시 +조회해야한다.

+
+
Returns
+

성공하면 1, 아니면 0을 반환

+
+
Return type
+

int

+
+
+
+ +
+
+GetConditionNameList(self) → str[source]
+

조건검색 조건명 리스트를 받아온다.

+

서버에서 수신한 사용자 조건식을 조건식의 고유번호와 조건식 이름을 한 쌍으로 하는 문자열들로 전달합니다. +조건식 하나는 조건식의 고유번호와 조건식 이름이 구분자 ‘^’ 로 나뉘어져 있으며 각 조건식은 ‘;’ 로 나뉘어져 있습니다. +이 함수는 OnReceiveConditionVer() 이벤트에서 사용해야 합니다.

+
+
Returns
+

조건명 리스트 문자열

+
+
Return type
+

str

+
+
+

Examples

+
>>> GetConditionNameList()
+"1^내조건식1;2^내조건식2;5^내조건식3;..."
+
+
+
+ +
+
+SendCondition(self, strScrNo: str, strConditionName: str, nIndex: int, nSearch: int) → int[source]
+

조건검색 종목조회TR을 송신한다.

+

서버에 조건검색을 요청하는 함수입니다. +마지막 인자값으로 조건검색만 할것인지 실시간 조건검색도 수신할 것인지를 지정할 수 있습니다. +GetConditionNameList() 함수로 얻은 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. +리턴값 1이면 성공이며, 0이면 실패입니다. +요청한 조건식이 없거나 조건 고유번호와 조건명이 서로 안맞거나 조회횟수를 초과하는 경우 실패하게 됩니다.

+

단순 조건식에 맞는 종목을 조회하기 위해서는 조회구분을 0으로 하고, +실시간 조건검색을 하기 위해서는 조회구분을 1로 한다. +OnReceiveTrCondition() 으로 결과값이 온다. +연속조회가 필요한 경우에는 응답받는 곳에서 연속조회 여부에 따라 연속조회를 송신하면된다.

+
+
Parameters
+
    +
  • strScrNo (str) – 화면번호

  • +
  • strConditionName (str) – 조건식 이름

  • +
  • nIndex (int) – 조건식 인덱스

  • +
  • nSearch (int) – 조회구분 (0:일반조회, 1:실시간조회 (최초 일반조회 + 이후 실시간조회), 2:연속조회)

  • +
+
+
Returns
+

성공하면 1, 아니면 0을 반환

+
+
Return type
+

int

+
+
+
+ +
+
+SendConditionStop(self, strScrNo: str, strConditionName: str, nIndex: int) → None[source]
+

조건검색 실시간 중지TR을 송신한다.

+

실시간 조건검색을 중지할 때 사용하는 함수입니다. +조건식 조회할때 얻는 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다.

+

해당 조건명의 실시간 조건검색을 중지하거나, +다른 조건명으로 바꿀 때 이전 조건명으로 실시간 조건검색을 반드시 중지해야한다. +화면 종료시에도 실시간 조건검색을 한 조건명으로 전부 중지해줘야 한다.

+
+
Parameters
+
    +
  • strScrNo (str) – 화면번호

  • +
  • strConditionName (str) – 조건식 이름

  • +
  • nIndex (int) – 조건식 인덱스

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+GetCommDataEx(self, strTrCode: str, strRecordName: str)[source]
+

차트 조회 데이터를 배열로 받아온다.

+

조회 수신데이터 크기가 큰 차트데이터를 한번에 가져올 목적으로 만든 차트조회 전용함수입니다.

+

조회 데이터가 많은 차트 경우 GetCommData()로 항목당 하나씩 받아오는 것 보다 +한번에 데이터 전부를 받아서 사용자가 처리할 수 있도록 배열로 받는다.

+

※ Qt 기준으로 QVariant 타입의 배열을 반환하지만 PySide2 에서는 완전히 똑같이 지원하진 않습니다.

+
+
Parameters
+
    +
  • strTrCode (str) – TR코드

  • +
  • strRecordName (str) – 레코드명

  • +
+
+
Returns
+

조회 데이터 배열

+
+
Return type
+

QVariant

+
+
+
+ +
+
+SetRealRemove(self, strScrNo: str, strDelCode: str) → None[source]
+

종목별 실시간 해제.

+

실시간시세 해지 함수이며 화면번호와 종목코드를 이용해서 상세하게 설정할 수 있습니다.

+

※ A종목에 대한 실시간이 여러 화면번호로 중복 등록되어 있는 경우 특정 화면번호를 이용한 +SetRealRemove() 함수호출시 A종목의 실시간시세는 해지되지 않습니다.

+

SetRealReg() 함수로 실시간 등록한 종목만 실시간 해제 할 수 있다.

+
+
Parameters
+
    +
  • strScrNo (str) – 화면번호 (4자리) 또는 “ALL”

  • +
  • strDelCode (str) – 종목코드 또는 “ALL”

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+GetMarketType(self, sTrCode: str) → int[source]
+

주어진 종목코드의 시장구분값을 가져온다.

+
+
시장 구분:
    +
  • 0: 장내

  • +
  • 3: ELW

  • +
  • 4: 뮤추얼펀드

  • +
  • 5: 신주인수권

  • +
  • 6: 리츠

  • +
  • 8: ETF

  • +
  • 9: 하이일드펀드

  • +
  • 10: 코스닥

  • +
  • 30: K-OTC

  • +
  • 50: 코넥스 (KONEX)

  • +
+
+
+
+
Parameters
+

sTrCode (str) – 종목코드

+
+
Returns
+

시장 구분값

+
+
Return type
+

int

+
+
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.html new file mode 100644 index 00000000..be62af2c --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.html @@ -0,0 +1,249 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusDispatchSignature

A Signature object represents the overall signature of a function.

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature.KiwoomOpenApiPlusDispatchSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst, line 39); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst, line 39); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst, line 43); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst, line 43); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+DISPATCH_SIGNATURES_BY_NAME :Dict[str, KiwoomOpenApiPlusDispatchSignature][source]
+
+ +
+
+classmethod from_name(cls, name: str) → KiwoomOpenApiPlusDispatchSignature[source]
+
+ +
+
+classmethod names(cls) → List[str][source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.html new file mode 100644 index 00000000..98193902 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.html @@ -0,0 +1,294 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

KiwoomOpenApiPlusDynamicCallableRunnable

KiwoomOpenApiPlusDynamicCallable

Abstract base class for generic types.

+
+
+

Attributes

+ ++++ + + + + + + + + +

P

R

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.P[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.R[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallableRunnable(future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Sequence[Any])[source]
+
+
+run(self)[source]
+
+ +
+
+cancel(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallable(control: koapy.compat.pyside2.QtAxContainer.QAxWidget, name: str, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None)[source]
+

Bases: koapy.compat.pyside2.QtCore.QObject, Generic[P, R]

+

Abstract base class for generic types.

+

A generic type is typically declared by inheriting from +this class parameterized with one or more type variables. +For example, a generic mapping type might be defined as:

+
class Mapping(Generic[KT, VT]):
+    def __getitem__(self, key: KT) -> VT:
+        ...
+    # Etc.
+
+
+

This class can then be used as follows:

+
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
+    try:
+        return mapping[key]
+    except KeyError:
+        return default
+
+
+
+
+ready_runnable[source]
+
+ +
+
+bind_dynamic_call_args(self, *args, **kwargs) → List[Any][source]
+
+ +
+
+is_valid_return_type(self, result: Any) → bool[source]
+
+ +
+
+check_return_value(self, result: Any)[source]
+
+ +
+
+dynamic_call(self, args: Sequence[Any]) → R[source]
+
+ +
+
+dynamic_call_and_check(self, args: Sequence[Any]) → R[source]
+
+ +
+
+call(self, *args: P, **kwargs: P) → R[source]
+
+ +
+
+async_call(self, *args: P, **kwargs: P) → concurrent.futures.Future[source]
+
+ +
+
+on_ready_runnable(self, runnable: KiwoomOpenApiPlusDynamicCallableRunnable)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.html new file mode 100644 index 00000000..6f519ca0 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEntrypoint

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint.KiwoomOpenApiPlusEntrypoint(port=None, client_check_timeout=None)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin.KiwoomOpenApiPlusEntrypointMixin, koapy.utils.logging.Logging.Logging

+
+
+get_stub(self)[source]
+
+ +
+
+close_client(self)[source]
+
+ +
+
+close_server_proc(self)[source]
+
+ +
+
+close(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.html new file mode 100644 index 00000000..874db088 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEntrypointMixin

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin.KiwoomOpenApiPlusEntrypointMixin[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.html new file mode 100644 index 00000000..a9044893 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.html @@ -0,0 +1,642 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError

+
+

Module Contents

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.CallableReturnsInt[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.IntOrBool[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.CallableReturnsIntOrBool[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.IntCompatible[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.BoolCompatible[source]
+
+ +
+
+exception koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusError(message: Optional[str] = None)[source]
+

Bases: Exception

+

Common base class for all non-exit exceptions.

+
+
+property message(self)[source]
+
+ +
+
+classmethod try_or_raise(cls, arg: IntCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) → IntCompatible[source]
+
+ +
+
+classmethod try_or_raise_boolean(cls, arg: BoolCompatible, message: str, except_callback: Optional[Callable] = None) → BoolCompatible[source]
+
+ +
+
+classmethod get_error_message_by_code(cls, code: int, default: Optional[str] = None)[source]
+
+ +
+ +
+
+exception koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusNegativeReturnCodeError(code: int, message: Optional[str] = None)[source]
+

Bases: KiwoomOpenApiPlusError

+

Common base class for all non-exit exceptions.

+
+
+OP_ERR_NONE = 0[source]
+
+ +
+
+OP_ERR_FAIL[source]
+
+ +
+
+OP_ERR_COND_NOTFOUND[source]
+
+ +
+
+OP_ERR_COND_MISMATCH[source]
+
+ +
+
+OP_ERR_COND_OVERFLOW[source]
+
+ +
+
+OP_ERR_TR_FAIL[source]
+
+ +
+
+OP_ERR_LOGIN[source]
+
+ +
+
+OP_ERR_CONNECT[source]
+
+ +
+
+OP_ERR_VERSION[source]
+
+ +
+
+OP_ERR_FIREWALL[source]
+
+ +
+
+OP_ERR_MEMORY[source]
+
+ +
+
+OP_ERR_INPUT[source]
+
+ +
+
+OP_ERR_SOCKET_CLOSED[source]
+
+ +
+
+OP_ERR_SISE_OVERFLOW[source]
+
+ +
+
+OP_ERR_RQ_STRUCT_FAIL[source]
+
+ +
+
+OP_ERR_RQ_STRING_FAIL[source]
+
+ +
+
+OP_ERR_NO_DATA[source]
+
+ +
+
+OP_ERR_OVER_MAX_DATA[source]
+
+ +
+
+OP_ERR_DATA_RCV_FAIL[source]
+
+ +
+
+OP_ERR_OVER_MAX_FID[source]
+
+ +
+
+OP_ERR_REAL_CANCEL[source]
+
+ +
+
+OP_ERR_ORD_WRONG_INPUT[source]
+
+ +
+
+OP_ERR_ORD_WRONG_ACCTNO[source]
+
+ +
+
+OP_ERR_OTHER_ACC_USE[source]
+
+ +
+
+OP_ERR_MIS_2BILL_EXC[source]
+
+ +
+
+OP_ERR_MIS_5BILL_EXC[source]
+
+ +
+
+OP_ERR_MIS_1PER_EXC[source]
+
+ +
+
+OP_ERR_MIS_3PER_EXC[source]
+
+ +
+
+OP_ERR_SEND_FAIL[source]
+
+ +
+
+OP_ERR_ORD_OVERFLOW[source]
+
+ +
+
+OP_ERR_ORD_OVERFLOW2[source]
+
+ +
+
+OP_ERR_MIS_300CNT_EXC[source]
+
+ +
+
+OP_ERR_MIS_500CNT_EXC[source]
+
+ +
+
+OP_ERR_ORD_WRONG_ACCTINFO[source]
+
+ +
+
+OP_ERR_ORD_SYMCODE_EMPTY[source]
+
+ +
+
+MSG_ERR_NONE = 정상처리[source]
+
+ +
+
+MSG_ERR_FAIL = 실패[source]
+
+ +
+
+MSG_ERR_COND_NOTFOUND = 조건번호 없음[source]
+
+ +
+
+MSG_ERR_COND_MISMATCH = 조건번호와 조건식 틀림[source]
+
+ +
+
+MSG_ERR_COND_OVERFLOW = 조건검색 조회요청 초과[source]
+
+ +
+
+MSG_ERR_TR_FAIL = 전문 처리 실패[source]
+
+ +
+
+MSG_ERR_LOGIN = 사용자정보 교환 실패[source]
+
+ +
+
+MSG_ERR_CONNECT = 서버접속 실패[source]
+
+ +
+
+MSG_ERR_VERSION = 버전처리 실패[source]
+
+ +
+
+MSG_ERR_FIREWALL = 개인방화벽 실패[source]
+
+ +
+
+MSG_ERR_MEMORY = 메모리보호 실패[source]
+
+ +
+
+MSG_ERR_INPUT = 함수입력값 오류[source]
+
+ +
+
+MSG_ERR_SOCKET_CLOSED = 통신 연결종료[source]
+
+ +
+
+MSG_ERR_SISE_OVERFLOW = 시세조회 과부하[source]
+
+ +
+
+MSG_ERR_RQ_STRUCT_FAIL = 전문작성 초기화 실패[source]
+
+ +
+
+MSG_ERR_RQ_STRING_FAIL = 전문작성 입력값 오류[source]
+
+ +
+
+MSG_ERR_NO_DATA = 데이터 없음[source]
+
+ +
+
+MSG_ERR_OVER_MAX_DATA = 조회 가능한 종목수 초과[source]
+
+ +
+
+MSG_ERR_DATA_RCV_FAIL = 데이터수신 실패[source]
+
+ +
+
+MSG_ERR_OVER_MAX_FID = 조회 가능한 FID수 초과[source]
+
+ +
+
+MSG_ERR_REAL_CANCEL = 실시간 해제 오류[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_INPUT = 입력값 오류[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_ACCTNO = 계좌 비밀번호 없음[source]
+
+ +
+
+MSG_ERR_OTHER_ACC_USE = 타인계좌사용 오류[source]
+
+ +
+
+MSG_ERR_MIS_2BILL_EXC = 주문가격이 20억원을 초과[source]
+
+ +
+
+MSG_ERR_MIS_5BILL_EXC = 주문가격이 50억원을 초과[source]
+
+ +
+
+MSG_ERR_MIS_1PER_EXC = 주문수량이 총발행주수의 1%초과오류[source]
+
+ +
+
+MSG_ERR_MIS_3PER_EXC = 주문수량이 총발행주수의 3%초과오류[source]
+
+ +
+
+MSG_ERR_SEND_FAIL = 주문전송 실패[source]
+
+ +
+
+MSG_ERR_ORD_OVERFLOW = 주문전송 과부하[source]
+
+ +
+
+MSG_ERR_ORD_OVERFLOW2 = 주문전송 과부하[source]
+
+ +
+
+MSG_ERR_MIS_300CNT_EXC = 주문수량 300계약 초과[source]
+
+ +
+
+MSG_ERR_MIS_500CNT_EXC = 주문수량 500계약 초과[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_ACCTINFO = 계좌정보없음[source]
+
+ +
+
+MSG_ERR_ORD_SYMCODE_EMPTY = 종목코드없음[source]
+
+ +
+
+ERROR_MESSAGE_BY_CODE[source]
+
+ +
+
+classmethod get_error_message_by_code(cls, code: int, default: Optional[str] = None)[source]
+
+ +
+
+classmethod check_code_or_raise(cls, code: int)[source]
+
+ +
+
+classmethod wrap_to_check_code_or_raise(cls, func: CallableReturnsInt) → CallableReturnsInt[source]
+
+ +
+
+classmethod try_or_raise(cls, arg: IntCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) → IntCompatible[source]
+
+ +
+
+property code(self)[source]
+
+ +
+ +
+
+exception koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusBooleanReturnCodeError(code: Union[int, bool], message: Optional[str] = None)[source]
+

Bases: KiwoomOpenApiPlusError

+

Common base class for all non-exit exceptions.

+
+
+OP_ERR_SUCCESS = 1[source]
+
+ +
+
+OP_ERR_FAILURE = 0[source]
+
+ +
+
+classmethod check_code_or_raise(cls, code: IntOrBool, message: Optional[str] = None) → IntOrBool[source]
+
+ +
+
+classmethod wrap_to_check_code_or_raise(cls, func: CallableReturnsIntOrBool, message: Optional[str] = None) → CallableReturnsIntOrBool[source]
+
+ +
+
+classmethod try_or_raise(cls, arg: BoolCompatible, message: Optional[str] = None, except_callback: Optional[Callable] = None) → BoolCompatible[source]
+
+ +
+
+property code(self)[source]
+
+ +
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.html new file mode 100644 index 00000000..25458fac --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.html @@ -0,0 +1,382 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEventFunctions

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions.KiwoomOpenApiPlusEventFunctions[source]
+
+
+OnReceiveTrData(self, sScrNo: str, sRQName: str, sTrCode: str, sRecordName: str, sPrevNext: str, nDataLength: int, sErrorCode: str, sMessage: str, sSplmMsg: str) → None[source]
+

서버통신 후 데이터를 받은 시점을 알려준다.

+

요청했던 조회데이터를 수신했을때 발생됩니다. +수신된 데이터는 이 이벤트내부에서 GetCommData() 함수를 이용해서 얻어올 수 있습니다.

+
+
파라미터 매핑:
    +
  • sRQName = CommRqData() 의 sRQName과 매핑되는 이름이다.

  • +
  • sTrCode = CommRqData() 의 sTrCode과 매핑되는 이름이다.

  • +
+
+
+
+
Parameters
+
    +
  • sScrNo (str) – 화면번호

  • +
  • sRQName (str) – 사용자 구분명

  • +
  • sTrCode (str) – TR 코드

  • +
  • sRecordName (str) – 레코드 명

  • +
  • sPrevNext (str) – 연속조회 유무 (0:추가조회 데이터 없음, 2:추가조회 데이터 있음)

  • +
  • nDataLength (str) – 사용안함

  • +
  • sErrorCode (str) – 사용안함

  • +
  • sMessage (str) – 사용안함

  • +
  • sSplmMsg (str) – 사용안함

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveRealData(self, sRealKey: str, sRealType: str, sRealData: str) → None[source]
+

실시간데이터를 받은 시점을 알려준다.

+

실시간시세 데이터가 수신될때마다 종목단위로 발생됩니다. +SetRealReg() 함수로 등록한 실시간 데이터도 이 이벤트로 전달됩니다. +GetCommRealData() 함수를 이용해서 수신된 데이터를 얻을수 있습니다.

+
+
Parameters
+
    +
  • sRealKey (str) – 종목코드

  • +
  • sRealType (str) – 실시간 타입

  • +
  • sRealData (str) – 실시간 데이터전문 (사용불가)

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveMsg(self, sScrNo: str, sRQName: str, sTrCode: str, sMsg: str) → None[source]
+

서버통신 후 메시지를 받은 시점을 알려준다.

+

주문전송 또는 데이터 조회요청 후 서버 메시지가 수신됩니다. +※ 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다.

+
+
파라미터 매핑:
    +
  • sScrNo = CommRqData() 의 sScrNo와 매핑된다.

  • +
  • sRQName = CommRqData() 의 sRQName 와 매핑된다.

  • +
  • sTrCode = CommRqData() 의 sTrCode 와 매핑된다.

  • +
+
+
메시지 예시:
    +
  • “조회가 완료되었습니다.”

  • +
  • “증거금 부족으로 주문이 거부되었습니다.”

  • +
  • “정정할 원주문 내역이 없습니다.”

  • +
  • “비밀번호 입력을 확인해주시기 바랍니다.”

  • +
+
+
+
+
Parameters
+

sScrNo – str, sRQName: str, sTrCode: str, sMsg: str

+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveChejanData(self, sGubun: str, nItemCnt: int, sFIdList: str) → None[source]
+

체결데이터를 받은 시점을 알려준다.

+

주문전송 후 주문접수, 체결통보, 잔고통보를 수신할 때 마다 발생됩니다. +GetChejanData() 함수를 이용해서 FID 항목별 값을 얻을수 있습니다.

+
+
Parameters
+
    +
  • sGubun (str) – 체결구분 (0:주문체결통보, 1:국내주식 잔고통보, 4:파생상품 잔고통보)

  • +
  • nItemCnt (int) – 아이템 개수

  • +
  • sFIdList (str) – 데이터 리스트 (‘;’ 구분자)

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+OnEventConnect(self, nErrCode: int) → None[source]
+

서버 접속 관련 이벤트.

+

로그인 처리 이벤트입니다. 성공이면 인자값 nErrCode가 0이며 에러는 다음과 같은 값이 전달됩니다.

+
+
에러코드 구분:
    +
  • OP_ERR_LOGIN(-100): 사용자 정보교환 실패

  • +
  • OP_ERR_CONNECT(-101): 서버접속 실패

  • +
  • OP_ERR_VERSION(-102): 버전처리 실패

  • +
+
+
+
+
Parameters
+

nErrCode (int) – 에러코드 (0:로그인 성공, 음수:실패)

+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveInvestRealData(self, sRealKey: str) → None[source]
+

더 이상 지원하지 않는 함수.

+
+ +
+
+OnReceiveRealCondition(self, sTrCode: str, strType: str, strConditionName: str, strConditionIndex: str) → None[source]
+

조건검색 실시간 편입,이탈 종목을 받을 시점을 알려준다.

+

실시간 조건검색 요청으로 신규종목이 편입되거나 기존 종목이 이탈될때 마다 발생됩니다. +※ 편입되었다가 순간적으로 다시 이탈되는 종목에대한 신호는 조건검색 서버마다 차이가 발생할 수 있습니다.

+

strConditionName 에 해당하는 종목이 실시간으로 들어옴. +strType 으로 편입된 종목인지 이탈된 종목인지 구분한다.

+
+
Parameters
+
    +
  • sTrCode (str) – 종목코드

  • +
  • strType (str) – 편입/이탈 구분 (I:편입, D:이탈)

  • +
  • strConditionName (str) – 조건식 이름

  • +
  • strConditionIndex (str) – 조건식 인덱스

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveTrCondition(self, sScrNo: str, strCodeList: str, strConditionName: str, nIndex: int, nNext: int) → None[source]
+

조건검색 조회응답으로 종목리스트를 받는 시점.

+

조건검색 요청에대한 서버 응답 수신시 발생하는 이벤트입니다. +종목코드 리스트는 각 종목코드가 ‘;’ 로 구분되서 전달됩니다.

+
+
Parameters
+
    +
  • sScrNo (str) – 화면번호

  • +
  • strCodeList (str) – 종목리스트 (‘;’ 구분자)

  • +
  • strConditionName (str) – 조건식 이름

  • +
  • nIndex (int) – 조건식 인덱스

  • +
  • nNext (int) – 연속조회 여부 (2:연속조회, 0:연속조회 없음)

  • +
+
+
Returns
+

None

+
+
+
+ +
+
+OnReceiveConditionVer(self, lRet: int, sMsg: str) → None[source]
+

로컬에 사용자 조건식 저장 성공 여부를 확인하는 시점.

+

저장된 사용자 조건식 불러오기 요청에 대한 응답 수신시 발생되는 이벤트입니다.

+
+
Parameters
+
    +
  • lRet (int) – 사용자 조건식 저장 성공여부 (1:성공, 나머지:실패)

  • +
  • sMsg (str) – 호출결과 메시지

  • +
+
+
Returns
+

None

+
+
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.html new file mode 100644 index 00000000..f46031aa --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.html @@ -0,0 +1,251 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions.KiwoomOpenApiPlusEventHandlerFunctions

+
+
+property control(self)[source]
+
+ +
+
+property observer(self)[source]
+
+ +
+
+classmethod names(cls)[source]
+
+ +
+
+slots(self)[source]
+
+ +
+
+connect(self)[source]
+
+ +
+
+disconnect(self)[source]
+
+ +
+
+on_enter(self)[source]
+
+ +
+
+on_exit(self, exc_type=None, exc_value=None, traceback=None)[source]
+
+ +
+
+add_callback(self, callback, *args, **kwargs)[source]
+
+ +
+
+enter(self)[source]
+
+ +
+
+exit(self, exc_type=None, exc_value=None, traceback=None)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+close(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.html new file mode 100644 index 00000000..544d4354 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.html @@ -0,0 +1,225 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEventHandlerFunctions

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions.KiwoomOpenApiPlusEventHandlerFunctions[source]
+
+
+abstract OnEventConnect(self, errcode)[source]
+
+ +
+
+abstract OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+abstract OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+abstract OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+abstract OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+abstract OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+
+abstract OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+abstract OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.html new file mode 100644 index 00000000..5060738e --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.html @@ -0,0 +1,249 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEventHandlerSignature

A Signature object represents the overall signature of a function.

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature.KiwoomOpenApiPlusEventHandlerSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst, line 39); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst, line 39); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst, line 43); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst, line 43); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+EVENT_HANDLER_SIGNATURES_BY_NAME :Dict[str, KiwoomOpenApiPlusEventHandlerSignature][source]
+
+ +
+
+classmethod from_name(cls, name: str) → KiwoomOpenApiPlusEventHandlerSignature[source]
+
+ +
+
+classmethod names(cls) → List[str][source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.html new file mode 100644 index 00000000..2b2155b3 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.html @@ -0,0 +1,238 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusLoggingEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler, koapy.utils.logging.Logging.Logging

+
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+

[OnReceiveMsg()이벤트]

+
+

OnReceiveMsg( +BSTR sScrNo, // 화면번호 +BSTR sRQName, // 사용자 구분명 +BSTR sTrCode, // TR이름 +BSTR sMsg // 서버에서 전달하는 메시지 +)

+

서버통신 후 수신한 메시지를 알려줍니다. +메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 +이 코드번호로 분류하시면 안됩니다.

+
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.html new file mode 100644 index 00000000..bb4488c2 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.html @@ -0,0 +1,218 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusQAxWidget

KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget.KiwoomOpenApiPlusQAxWidget(c: Optional[str] = None, parent: Optional[koapy.compat.pyside2.QtWidgets.QWidget] = None, f: koapy.compat.pyside2.QtCore.Qt.WindowFlags = Qt.WindowFlags())           KiwoomOpenApiPlusQAxWidget(parent: Optional[koapy.compat.pyside2.QtWidgets.QWidget] = None, f: koapy.compat.pyside2.QtCore.Qt.WindowFlags = Qt.WindowFlags())[source]
+

Bases: koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging, koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetMixin

+

KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 +KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다.

+
+
+CLSID = {A1574A0D-6BFA-4BD7-9020-DED88711818D}[source]
+
+ +
+
+PROGID = KHOPENAPI.KHOpenApiCtrl.1[source]
+
+ +
+
+METHOD_NAMES[source]
+
+ +
+
+EVENT_NAMES[source]
+
+ +
+
+changeEvent(self, event)[source]
+
+ +
+
+closeEvent(self, event)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.html new file mode 100644 index 00000000..3dadace3 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.html @@ -0,0 +1,651 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusQAxWidgetUniversalMixin

일차적으로 KiwoomOpenApiPlusQAxWidget 객체에 대해 사용될 수 있는 Mixin 이지만,

KiwoomOpenApiPlusQAxWidgetServerSideMixin

KiwoomOpenApiPlusQAxWidget 객체에 대해 Server-Side 에서만 사용되는 Mixin 입니다.

KiwoomOpenApiPlusQAxWidgetMixin

KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetUniversalMixin[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions

+

일차적으로 KiwoomOpenApiPlusQAxWidget 객체에 대해 사용될 수 있는 Mixin 이지만, +넓게는 다른 KiwoomOpenApiPlusDispatchFunctions 인터페이스를 지원하는 모든 객체에서 사용될 수 있는, +단순하면서도 유니버셜한 메소드들이 구현되어 있는 Mixin 입니다.

+
+
+IsConnected(self)[source]
+

키움증권 서버에 접속되었는지 여부를 반환합니다.

+
+ +
+
+ShowAccountWindow(self)[source]
+

계좌 비밀번호 및 자동 로그인 처리 관련 설정창을 표시합니다.

+
+ +
+
+GetServerGubun(self)[source]
+

접속된 서버의 종류를 확인해 구분값을 반환합니다.

+
+ +
+
+IsSimulationServer(self)[source]
+

모의투자 서버 접속 여부를 확인해 반환합니다.

+
+ +
+
+IsRealServer(self)[source]
+

실 서버 접속 여부를 확인해 반환합니다.

+
+ +
+
+GetMasterStockInfo(self, code)[source]
+

주식의 종목분류, 시장구분등의 정보를 제공합니다.

+
+ +
+
+GetMasterStockInfoAsDict(self, code)[source]
+

주식의 종목분류, 시장구분등의 정보를 딕셔너리 형태로 가공하여 제공합니다.

+
+ +
+
+SetConditionSearchFlag(self, flag)[source]
+

조건 검색시 동작과 관련된 플래그를 설정합니다.

+
+ +
+
+AddPriceToConditionSearchResult(self)[source]
+

조건 검색시 현재가를 함께 수신하도록 설정합니다.

+
+ +
+
+DelPriceFromConditionSearchResult(self)[source]
+

조건 검색시 현재가를 함께 수신하지 않도록 설정합니다.

+
+ +
+
+GetUpjongCode(self, code)[source]
+

업종코드 목록을 반환합니다.

+

인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. +0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100

+
+ +
+
+GetUpjongCodeAsList(self, code)[source]
+

업종코드 목록을 리스트 형태로 가공하여 반환합니다.

+

인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. +0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100

+
+ +
+
+GetUpjongNameByCode(self, code)[source]
+

주어진 업종코드의 이름을 반환합니다.

+
+ +
+
+IsOrderWarningETF(self, code)[source]
+

ETF 의 투자유의 종목 여부를 반환합니다.

+

투자유의 종목인 경우 “1” 값이 리턴, +그렇지 않은 경우 “0” 값 리턴. +ETF가 아닌 종목을 입력시 “0” 값 리턴.

+
+ +
+
+IsOrderWarningETFAsBoolean(self, code)[source]
+

ETF 의 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다.

+
+ +
+
+IsOrderWarningStock(self, code)[source]
+

주식 전종목 대상 투자유의 종목 여부를 반환합니다.

+

리턴 값 - “0”:해당없음, “2”:정리매매, “3”:단기과열, “4”:투자위험, “5”:투자경고

+
+ +
+
+IsOrderWarningStockAsBoolean(self, code)[source]
+

주식 전종목 대상 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다.

+
+ +
+
+GetMasterListedStockCntEx(self, code)[source]
+

종목의 상장 주식수를 반환합니다.

+

기존의 GetMasterListedStockCnt() 함수 사용시 발생할 수 있는 오버플로우 문제를 해결합니다.

+
+ +
+
+GetMasterListedStockCntExAsInt(self, code)[source]
+

종목의 상장 주식수를 정수 형태로 변환하여 반환합니다.

+
+ +
+
+GetCodeListByMarketAsList(self, market: Optional[Union[str, int]] = None)[source]
+

시장의 종목 코드 목록를 리스트 형태로 가공하여 반환합니다.

+
+ +
+
+GetNameListByMarketAsList(self, market: Optional[Union[str, int]] = None)[source]
+

시장의 종목 이름 목록를 리스트 형태로 가공하여 반환합니다.

+
+ +
+
+GetUserId(self)[source]
+

사용자 ID 를 반환합니다.

+
+ +
+
+GetUserName(self)[source]
+

사용자 이름을 반환합니다.

+
+ +
+
+GetAccountCount(self)[source]
+

계좌 개수를 반환합니다.

+
+ +
+
+GetAccountList(self)[source]
+

계좌 목록을 리스트 형태로 가공하여 반환합니다.

+
+ +
+
+GetKeyboardSecurityStatus(self)[source]
+

키보드 보안 설정 상태를 반환합니다.

+
+ +
+
+IsKeyboardSecurityEnabled(self)[source]
+

키보드 보안 설정 상태를 불리언 형태로 변환하여 반환합니다.

+
+ +
+
+GetFirewallStatus(self)[source]
+

방화벽 설정 상태를 반환합니다.

+
+ +
+
+IsFirewallEnabled(self)[source]
+

방화벽 설정 상태를 불리언 형태로 변환하여 반환합니다.

+
+ +
+
+GetFirstAvailableAccount(self)[source]
+

확인 가능한 첫번째 계좌번호를 반환합니다.

+
+ +
+
+GetMasterStockStateAsList(self, code: str)[source]
+

입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 +리스트 형태로 가공하여 전달합니다.

+
+ +
+
+GetKospiCodeList(self)[source]
+

장내 종목 코드 목록을 반환합니다.

+
+ +
+
+GetKosdaqCodeList(self)[source]
+

코스닥 시장내 종목 코드 목록을 반환합니다.

+
+ +
+
+GetGeneralCodeList(self, include_preferred_stock: bool = False, include_etn: bool = False, include_etf: bool = False, include_mutual_fund: bool = False, include_reits: bool = False, include_kosdaq: bool = False)[source]
+

장내 종목 코드 목록중 특정 그룹을 포함시키고 혹은 제거하고 반환합니다.

+
+ +
+
+GetStockStates(self, code: str)[source]
+

입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다.

+
+ +
+
+GetSurveillanceFlag(self, code: str)[source]
+

입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목)

+
+ +
+
+IsSuspended(self, code: str)[source]
+

거래정지 여부를 반환합니다.

+
+ +
+
+IsUnderSurveillance(self, code: str)[source]
+

감리종목 여부를 반환합니다.

+
+ +
+
+IsUnderAdministration(self, code: str)[source]
+

관리종목 여부를 반환합니다.

+
+ +
+
+IsFlaggedForCaution(self, code: str)[source]
+

감리구분이 정상이 아니거나 상태값중 투자유의종목으로 지정된 경우 참을 반환합니다.

+
+ +
+
+IsNotNormal(self, code: str)[source]
+

감리구분이 정상이 아니거나 상태값중 거래정지, 감리종목, 관리종목, 투자유의종목 등으로 지정된 경우 참을 반환합니다.

+
+ +
+
+IsNormal(self, code: str)[source]
+

감리구분이 정상이고 별다른 이상 상태값이 없는 경우 참을 반환합니다.

+
+ +
+
+GetConditionFilePath(self)[source]
+

조건식 데이터를 로드한 후 생성되는 조건검색 관련 데이터 파일의 경로를 반환합니다.

+
+ +
+
+GetConditionNameListAsList(self)[source]
+

조건식 데이터를 로드한 후 확인 가능한 조건식 목록을 리스트 형태로 가공하여 반환합니다.

+
+ +
+
+GetAutoLoginDatPath(self)[source]
+

자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일의 경로를 반환합니다.

+
+ +
+
+IsAutoLoginEnabled(self)[source]
+

자동 로그인 설정 여부를 반환합니다.

+

자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는지의 여부를 확인합니다.

+
+ +
+
+DisableAutoLogin(self)[source]
+

자동 로그인 설정을 해제합니다.

+

자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는 경우 해당 파일을 삭제합니다.

+
+ +
+
+classmethod RunScriptInSubprocess_WithData(cls, main: Callable[Ellipsis, Any], data: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False, stdin: Optional[int] = subprocess.PIPE, stdout: Optional[int] = None)[source]
+
+ +
+
+classmethod LoginUsingPywinauto_Impl(cls, credentials: Optional[Mapping[str, Any]] = None)[source]
+
+ +
+
+classmethod LoginUsingPywinauto_RunScriptInSubprocess(cls, credentials: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False)[source]
+
+ +
+
+LoginUsingPywinauto(self, credentials: Optional[Mapping[str, Any]] = None, wait: bool = True, timeout: bool = None, check: bool = True)[source]
+

자식 프로세스 내에서 pywinauto 를 사용해 로그인 처리를 자동으로 진행합니다.

+
+ +
+
+CommConnectAndThen(self, credentials: Mapping[str, Any], callback: Callable[[int], Any]) → int[source]
+
+CommConnectAndThen(self, credentials: Mapping[str, Any]) → int
+
+CommConnectAndThen(self, callback: Callable[[int], Any]) → int
+
+CommConnectAndThen(self) → int
+

로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 특정 콜백 함수를 실행합니다.

+
+ +
+
+Connect(self, credentials: Optional[Mapping[str, Any]] = None) → int[source]
+

로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 확인 가능한 에러코드 값을 반환합니다.

+
+ +
+
+EnsureConnectedAndThen(self, credentials: Mapping[str, Any], callback: Callable[[int], Any]) → bool[source]
+
+EnsureConnectedAndThen(self, credentials: Mapping[str, Any]) → bool
+
+EnsureConnectedAndThen(self, callback: Callable[[int], Any]) → bool
+
+EnsureConnectedAndThen(self) → bool
+

로그인 여부를 확인하고 로그인 상태를 보장한 뒤에 주어진 콜백 함수를 실행합니다.

+

로그인 여부 확인시 로그인 되어있지 않다면 로그인을 진행한 뒤 주어진 콜백 함수를 실행합니다. +이미 로그인이 되어있다면 즉시 주어진 콜백 함수를 실행합니다.

+
+ +
+
+EnsureConnected(self, credentials: Optional[Mapping[str, Any]] = None) → bool[source]
+

로그인 상태를 보장하도록 합니다.

+

이미 로그인이 되어있는 경우 별다른 처리를 하지 않습니다. +로그인이 되어있지 않다면 로그인을 수행합니다.

+
+ +
+
+classmethod EnableAutoLoginUsingPywinauto_Impl(cls, account_passwords: Optional[Mapping[str, Any]] = None)[source]
+
+ +
+
+classmethod EnableAutoLoginUsingPywinauto_RunScriptInSubprocess(cls, account_passwords: Optional[Mapping[str, Any]] = None, wait: bool = False, timeout: bool = None, check: bool = False)[source]
+
+ +
+
+EnableAutoLoginUsingPywinauto(self, credentials: Optional[Mapping[str, Any]] = None, wait: bool = True, timeout: bool = None, check: bool = True)[source]
+

자식 프로세스 내에서 pywinauto 를 사용해 자동 로그인 설정을 자동으로 진행합니다.

+
+ +
+
+EnableAutoLogin(self, credentials: Optional[Mapping[str, Any]] = None)[source]
+

자동 로그인을 설정합니다.

+
+ +
+
+EnsureAutoLoginEnabled(self, credentials: Optional[Mapping[str, Any]] = None) → bool[source]
+

자동 로그인이 설정되어 있음을 보장하도록 합니다.

+

이미 자동 로그인이 설정 되어있는 경우 별다른 처리를 하지 않습니다. +자동 로그인이 설정되어 있지 않다면 자동 로그인을 설정을 처리합니다.

+
+ +
+
+classmethod HandleVersionUpgradeUsingPywinauto_Impl(cls, pid)[source]
+
+ +
+
+classmethod HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess(cls, pid: int, wait: bool = False, timeout: bool = None, check: bool = False)[source]
+
+ +
+
+HandleVersionUpgradeUsingPywinauto(self, pid: int, wait: bool = True, timeout: bool = None, check: bool = True)[source]
+

자식 프로세스 내에서 pywinauto 를 사용해 버전 업그레이드 처리를 자동으로 진행합니다.

+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetServerSideMixin[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions, koapy.utils.logging.Logging.Logging

+

KiwoomOpenApiPlusQAxWidget 객체에 대해 Server-Side 에서만 사용되는 Mixin 입니다.

+

주로 서버 환경에서만 확인하거나 처리가 가능한 아래 기능들을 커버합니다:

+
+
    +
  • 조건검색식 로드

  • +
  • 조회 횟수 제한 회피 기능

  • +
+
+
+
+LoadCondition(self) → int[source]
+

조건검색 관련 조건식을 불러옵니다.

+
+ +
+
+IsConditionLoaded(self) → bool[source]
+

조건식이 로드 되었는지 여부를 반환합니다.

+
+ +
+
+EnsureConditionLoaded(self, force: bool = False) → int[source]
+

조건식이 로드됨을 보장하도록 합니다.

+

이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. +조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다.

+
+ +
+
+CommRqDataWithInputs(self, rqname: str, trcode: str, prevnext: Union[str, int], scrnno: str, inputs: Optional[Dict[str, str]] = None) → int[source]
+

CommRqData() 호출 이전에 주어진 입력값을로 SetInputValue() 호출을 통한 입력값 설정을 진행합니다. +이후 CommRqData() 를 호출합니다.

+
+ +
+
+AtomicCommRqData(self, rqname: str, trcode: str, prevnext: Union[str, int], scrnno: str, inputs: Optional[Dict[str, str]] = None) → int[source]
+

SetInputValue() 호출을 통한 입력값 설정 및 CommRqData() 호출을 하나의 단위로 처리할 수 있도록 Lock 을 걸고 처리합니다.

+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetMixin[source]
+

Bases: KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin

+

KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 +KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다.

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.html new file mode 100644 index 00000000..0c88b2f1 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.html @@ -0,0 +1,243 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusCommRqDataRateLimiter

[조회횟수 제한 관련 가이드]

KiwoomOpenApiPlusSendOrderRateLimiter

KiwoomOpenApiPlusSendConditionRateLimiter

[조건검색 제한]

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusCommRqDataRateLimiter[source]
+

Bases: koapy.utils.rate_limiting.RateLimiter.CompositeTimeWindowRateLimiter

+
+
[조회횟수 제한 관련 가이드]
    +
  • 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기

  • +
  • 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기

  • +
  • 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기

  • +
+
+
+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusSendOrderRateLimiter[source]
+

Bases: koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusSendConditionRateLimiter(comm_rate_limiter)[source]
+

Bases: koapy.utils.rate_limiting.RateLimiter.RateLimiter

+
+
[조건검색 제한]
    +
  • 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다.

  • +
+
+
[조건검색 제한]

조건검색 요청은 1초당 5회 조회횟수 제한에 포함됩니다. +동일 조건식에 대한 조건검색 요청은 1분에 1회로 제한됩니다. +조건검색 결과가 100종목을 넘게 되면 해당조건은 실시간 조건검색 신호를 수신할 수 없습니다. +실시간 조건검색은 최대 10개까지 사용 가능합니다.

+
+
+
+
+get_limiter_per_condition(self, condition_name, condition_index)[source]
+
+ +
+
+check_sleep_seconds(self, fn, *args, **kwargs)[source]
+
+ +
+
+add_call_history(self, fn, *args, **kwargs)[source]
+
+ +
+
+sleep_if_necessary(self, fn, *args, **kwargs)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.html new file mode 100644 index 00000000..7e65c6ee --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.html @@ -0,0 +1,366 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusRealType

+
+
+

Functions

+ ++++ + + + + + +

main()

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.KiwoomOpenApiPlusRealType(gidc: Optional[str] = None, desc: Optional[str] = None, nfid: Optional[int] = None, fids: Optional[List[int]] = None)[source]
+

Bases: koapy.utils.serialization.JsonSerializable, koapy.utils.logging.Logging.Logging

+
+
+class Fid(fid: Optional[int] = None, name: Optional[str] = None)[source]
+

Bases: koapy.utils.serialization.JsonSerializable

+
+
+FID_DUMP_FILEDIR[source]
+
+ +
+
+FID_DUMP_FILENAME = fid.csv[source]
+
+ +
+
+FID_DUMP_FILEPATH[source]
+
+ +
+
+FID_DUMP_PROCESSOR[source]
+
+ +
+
+FID_BY_FID :Dict[int, KiwoomOpenApiPlusRealType][source]
+
+ +
+
+FID_BY_NAME :Dict[str, KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod fids_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike]] = None, encoding: Optional[str] = None) → Dict[int, str][source]
+
+ +
+
+classmethod load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike]] = None)[source]
+
+ +
+
+classmethod from_fid(cls, fid: Union[str, int]) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod from_name(cls, name: str) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod get_name_by_fid(cls, fid: Union[str, int], default: Optional[str] = None) → Optional[str][source]
+
+ +
+ +
+
+REALTYPE_BY_DESC_DUMP_FILEDIR[source]
+
+ +
+
+REALTYPE_BY_DESC_DUMP_FILENAME = realtype_by_desc.json[source]
+
+ +
+
+REALTYPE_BY_DESC_DUMP_FILEPATH[source]
+
+ +
+
+REALTYPE_BY_DESC :Dict[str, KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod get_realtype_name_list(cls)[source]
+
+ +
+
+classmethod get_realtype_info_list(cls)[source]
+
+ +
+
+classmethod get_realtype_info_by_desc(cls, desc: str) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod get_realtype_info_by_name(cls, name: str) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod get_realtype_info_by_realtype_name(cls, name: str) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod from_name(cls, name: str) → Optional[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod get_fids_by_realtype_name(cls, name: str) → Optional[List[int]][source]
+
+ +
+
+classmethod get_fids_by_realtype_name_as_string(cls, name: str) → Optional[str][source]
+
+ +
+
+classmethod get_field_names_by_realtype_name(cls, name: str) → Optional[List[str]][source]
+
+ +
+
+classmethod realtypes_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None, encoding: Optional[str] = None, module_path: Optional[str] = None) → List[KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod realtype_by_desc_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None) → Dict[str, KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod dump_realtype_by_desc(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None, encoding: Optional[str] = None)[source]
+
+ +
+
+classmethod realtype_by_desc_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, encoding: Optional[str] = None) → Dict[str, KiwoomOpenApiPlusRealType][source]
+
+ +
+
+classmethod load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None)[source]
+
+ +
+
+classmethod load_from_datfile(cls, dat_file: Optional[Union[str, os.PathLike, BinaryIO]] = None)[source]
+
+ +
+
+classmethod load(cls)[source]
+
+ +
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.main()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.html new file mode 100644 index 00000000..7246a00a --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.html @@ -0,0 +1,231 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusScreenManager

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager.KiwoomOpenApiPlusScreenManager(control: Optional[koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions] = None)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+MAXIMUM_NUMBER_OF_SCREENS = 200[source]
+
+ +
+
+static number_to_screen_no(number: int) → str[source]
+
+ +
+
+static screen_no_to_number(screen_no: str) → int[source]
+
+ +
+
+is_inuse(self, screen_no: str) → bool[source]
+
+ +
+
+get_single_free_screen(self, exclude: Optional[Collection[str]] = None) → str[source]
+
+ +
+
+get_multiple_free_screens(self, count: int) → List[str][source]
+
+ +
+
+get_free_screen(self, count: Optional[int] = None) → Union[str, List[str]][source]
+
+ +
+
+borrow_screen(self, screen_no: Optional[str] = None, reuse: bool = True, pop: bool = True) → str[source]
+
+ +
+
+return_screen(self, screen_no: str) → bool[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.html new file mode 100644 index 00000000..def8922b --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.html @@ -0,0 +1,261 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusSignalConnector

Abstract base class for generic types.

+
+
+

Attributes

+ ++++ + + + + + + + + +

P

R

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.P[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.R[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.KiwoomOpenApiPlusSignalConnector(name: str)[source]
+

Bases: koapy.utils.logging.Logging.Logging, Generic[P, R]

+

Abstract base class for generic types.

+

A generic type is typically declared by inheriting from +this class parameterized with one or more type variables. +For example, a generic mapping type might be defined as:

+
class Mapping(Generic[KT, VT]):
+    def __getitem__(self, key: KT) -> VT:
+        ...
+    # Etc.
+
+
+

This class can then be used as follows:

+
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
+    try:
+        return mapping[key]
+    except KeyError:
+        return default
+
+
+
+
+is_valid_slot(self, slot: Callable[Ellipsis, Any]) → bool[source]
+
+ +
+
+connect_to(self, control: koapy.compat.pyside2.QtAxContainer.QAxWidget)[source]
+
+ +
+
+disconnect_from(self, control: koapy.compat.pyside2.QtAxContainer.QAxWidget)[source]
+
+ +
+
+connect(self, slot: Callable[Ellipsis, Any])[source]
+
+ +
+
+disconnect(self, slot: Optional[Callable[Ellipsis, Any]] = None)[source]
+
+ +
+
+call(self, *args: P, **kwargs: P) → R[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.html new file mode 100644 index 00000000..929dc01a --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.html @@ -0,0 +1,273 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusSignature

A Signature object represents the overall signature of a function.

+
+
+

Attributes

+ ++++ + + + + + +

NoneType

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.NoneType[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature(name: str, parameters: Dict[str, inspect.Parameter] = None, return_annotation=Signature.empty)[source]
+

Bases: inspect.Signature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst, line 52); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst, line 52); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst, line 56); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst, line 56); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+PYTHONTYPE_TO_QTTYPE[source]
+
+ +
+
+COMTYPE_TO_PYTHONTYPE[source]
+
+ +
+
+property name(self) → str[source]
+
+ +
+
+to_pyside2_function_prototype(self) → str[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.html new file mode 100644 index 00000000..1fda2b44 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.html @@ -0,0 +1,334 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusTrInfo

+
+
+

Functions

+ ++++ + + + + + + + + +

main()

infer_fids_by_tr_outputs(output_filename=None)

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.KiwoomOpenApiPlusTrInfo(tr_code: Optional[str] = None, name: Optional[str] = None, tr_name: Optional[str] = None, tr_names_svr: Optional[str] = None, tr_type: Optional[str] = None, gfid: Optional[str] = None, inputs: Optional[Sequence[Field]] = None, single_outputs_name: Optional[str] = None, single_outputs: Optional[Sequence[Field]] = None, multi_outputs_name: Optional[str] = None, multi_outputs: Optional[Sequence[Field]] = None)[source]
+

Bases: koapy.utils.serialization.JsonSerializable, koapy.utils.logging.Logging.Logging

+
+
+class Field(name: Optional[str] = None, start: Optional[int] = None, offset: Optional[int] = None, fid: Optional[int] = None)[source]
+

Bases: koapy.utils.serialization.JsonSerializable

+
+ +
+
+TRINFO_BY_CODE_DUMP_FILEDIR[source]
+
+ +
+
+TRINFO_BY_CODE_DUMP_FILENAME = trinfo_by_code.json[source]
+
+ +
+
+TRINFO_BY_CODE_DUMP_FILEPATH[source]
+
+ +
+
+TRINFO_BY_CODE :Dict[str, KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+SINGLE_TO_MULTI_TRCODES = ['opt10072', 'opt10073', 'opt10075', 'opt10076', 'opt10085', 'optkwfid', 'optkwinv', 'optkwpro'][source]
+
+ +
+
+to_dict(self) → Dict[str, Any][source]
+
+ +
+
+classmethod from_dict(cls, dic: Dict[str, Any]) → KiwoomOpenApiPlusTrInfo[source]
+
+ +
+
+get_input_names(self) → List[str][source]
+
+ +
+
+get_single_output_names(self) → List[str][source]
+
+ +
+
+get_multi_output_names(self) → List[str][source]
+
+ +
+
+classmethod get_trcode_list(cls) → List[str][source]
+
+ +
+
+classmethod get_trinfo_list(cls) → List[KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod get_trinfo_by_code(cls, trcode: str) → Optional[KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod from_code(cls, trcode: str) → Optional[KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod from_encfile(cls, f: Union[str, os.PathLike, TextIO], tr_code: Optional[str] = None, encoding: Optional[str] = None) → KiwoomOpenApiPlusTrInfo[source]
+
+ +
+
+classmethod infos_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None, encoding: Optional[str] = None, module_path: Optional[str] = None) → List[KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod swap_output_types(cls, item: KiwoomOpenApiPlusTrInfo) → KiwoomOpenApiPlusTrInfo[source]
+
+ +
+
+classmethod trinfo_by_code_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None, post_process: bool = True) → Dict[str, KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod dump_trinfo_by_code(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, data_dir: Optional[str] = None, encoding: Optional[str] = None)[source]
+
+ +
+
+classmethod trinfo_by_code_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None, encoding: Optional[str] = None) → Dict[str, KiwoomOpenApiPlusTrInfo][source]
+
+ +
+
+classmethod load_from_dump_file(cls, dump_file: Optional[Union[str, os.PathLike, TextIO]] = None)[source]
+
+ +
+
+classmethod load_from_data_dir(cls, data_dir: Optional[Union[str, os.PathLike]] = None)[source]
+
+ +
+
+classmethod load(cls)[source]
+
+ +
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.main()[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.infer_fids_by_tr_outputs(output_filename=None)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.html new file mode 100644 index 00000000..a8b3134c --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.html @@ -0,0 +1,181 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib

+
+

Module Contents

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib.TYPELIB[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib.DISPATCH_OLE_ITEM[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib.EVENT_OLE_ITEM[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.html new file mode 100644 index 00000000..9f9093bd --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.html @@ -0,0 +1,221 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec

+
+

Module Contents

+
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.CONTROL_PROGID = KHOPENAPI.KHOpenApiCtrl.1[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.CONTROL_CLSID[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.DISPATCH_CLSID[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.EVENT_CLSID[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.MODULE_CLSID[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.TYPELIB_SPECS[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.TYPELIB_SPEC[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.TYPELIB_DLL_PATH[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.API_MODULE_PATH_FROM_DEFAULT_INSTALLATION[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.API_MODULE_PATH_FROM_TYPELIB_DLL[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec.API_MODULE_PATH[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.html new file mode 100644 index 00000000..67a61e29 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.html @@ -0,0 +1,261 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusVersionUpdater

+
+
+class koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater.KiwoomOpenApiPlusVersionUpdater(credentials)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+get_api_module_path(self)[source]
+
+ +
+
+get_autologin_dat(self)[source]
+
+ +
+
+is_autologin_enabled(self)[source]
+
+ +
+
+disable_autologin(self)[source]
+
+ +
+
+classmethod open_login_window_impl(cls)[source]
+
+ +
+
+open_login_window(self)[source]
+
+ +
+
+classmethod show_account_window_impl(cls)[source]
+
+ +
+
+show_account_window(self)[source]
+
+ +
+
+classmethod check_apply_simulation_window(cls)[source]
+
+ +
+
+classmethod login_using_pywinauto(cls, credentials)[source]
+
+ +
+
+classmethod enable_autologin_using_pywinauto(cls, credentials)[source]
+
+ +
+
+enable_autologin(self)[source]
+
+ +
+
+classmethod handle_version_upgrade_using_pywinauto(cls, pid)[source]
+
+ +
+
+try_version_update_using_pywinauto(self)[source]
+
+ +
+
+update_version_if_necessary(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.html new file mode 100644 index 00000000..23a317b1 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/index.html @@ -0,0 +1,202 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core

+
+

Subpackages

+ +
+
+

Submodules

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.html new file mode 100644 index 00000000..93a4d4fc --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

generate_python_stubs(dispatch_class_name=None, dispatch_file_path=None, event_class_name=None, event_file_path=None, encoding=None, force_overwrite=False)

+
+
+koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs.generate_python_stubs(dispatch_class_name=None, dispatch_file_path=None, event_class_name=None, event_file_path=None, encoding=None, force_overwrite=False)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.html new file mode 100644 index 00000000..e7b1a362 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.html @@ -0,0 +1,171 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.core.tools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.html new file mode 100644 index 00000000..67915101 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.html @@ -0,0 +1,205 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusServiceClient

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient.KiwoomOpenApiPlusServiceClient(host=None, port=None, credentials=None, thread_pool=None, check_timeout=None, **kwargs)[source]
+
+
+is_ready(self, timeout=None)[source]
+
+ +
+
+get_grpc_stub(self)[source]
+
+ +
+
+get_stub(self)[source]
+
+ +
+
+close(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.html new file mode 100644 index 00000000..e1ae9484 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusServiceClientSideDynamicCallable

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable.KiwoomOpenApiPlusServiceClientSideDynamicCallable(stub, name)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.html new file mode 100644 index 00000000..38a99f11 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.html @@ -0,0 +1,200 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusServiceClientSideSignalConnector

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector.KiwoomOpenApiPlusServiceClientSideSignalConnector(stub, name, executor)[source]
+
+
+shutdown(self)[source]
+
+ +
+
+connect(self, callback)[source]
+
+ +
+
+disconnect(self, callback)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.html new file mode 100644 index 00000000..4002ccf0 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.html @@ -0,0 +1,573 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusServiceClientStubCoreWrapper

KiwoomOpenApiPlusServiceServicer 에서 구현되어 이후 Stub 을 통해 제공되는

KiwoomOpenApiPlusServiceClientStubExtendedWrapper

제공되는 RPC 들을 활용한 여러 사용 케이스들을 구현합니다.

KiwoomOpenApiPlusServiceClientStubWrapper

KiwoomOpenApiPlusServiceClientStubCoreWrapper, KiwoomOpenApiPlusServiceClientStubExtendedWrapper 의 구현 및

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubCoreWrapper(stub, executor)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetUniversalMixin

+

KiwoomOpenApiPlusServiceServicer 에서 구현되어 이후 Stub 을 통해 제공되는 +RPC 들을 클라이언트에서 좀 더 쉽게 사용하기 위한 래퍼 함수들을 제공합니다.

+
+
+METHOD_NAMES[source]
+
+ +
+
+EVENT_NAMES[source]
+
+ +
+
+Call(self, name, *args)[source]
+

임의의 함수 호출을 위한 RPC 입니다.

+

함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 +호출결과를 응답 메시지를 통해 전달합니다.

+

함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다.

+
+ +
+
+LoginCall(self, credentials=None)[source]
+

키움증권 서버 연결 시나리오에 해당하는 RPC 입니다.

+

CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+TransactionCall(self, rqname, trcode, scrno, inputs, stop_condition=None)[source]
+

TR 요청에 해당하는 RPC 입니다.

+

CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 +추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. +해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다.

+

경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 +추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다.

+

일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 +내부적으로 호출됩니다.

+

서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 +대기시간이 발생할 수 있습니다.

+

최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. +몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, +TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다.

+
+ +
+
+OrderCall(self, rqname, scrno, account, order_type, code, quantity, price, quote_type, original_order_no=None)[source]
+

주문 요청에 해당하는 RPC 입니다.

+

SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 +주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다.

+

일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. +다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다.

+

이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다.

+

기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다.

+
+
거래 구분:
    +
  • 00: 지정가

  • +
  • 03: 시장가

  • +
  • 05: 조건부지정가

  • +
  • 06: 최유리지정가

  • +
  • 07: 최우선지정가

  • +
  • 10: 지정가IOC

  • +
  • 13: 시장가IOC

  • +
  • 16: 최유리IOC

  • +
  • 20: 지정가FOK

  • +
  • 23: 시장가FOK

  • +
  • 26: 최유리FOK

  • +
  • 61: 장전시간외종가

  • +
  • 62: 시간외단일가매매

  • +
  • 81: 장후시간외종가

  • +
+
+
+

※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다.

+
+
주문 유형:
    +
  • 1: 신규매수

  • +
  • 2: 신규매도

  • +
  • 3: 매수취소

  • +
  • 4: 매도취소

  • +
  • 5: 매수정정

  • +
  • 6: 매도정정

  • +
+
+
+
+
Parameters
+
    +
  • rqname (str) – 사용자 구분 요청명

  • +
  • scrno (str) – 화면번호 (4자리)

  • +
  • account (str) – 계좌번호 (10자리)

  • +
  • order_type (int) – 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정)

  • +
  • code (str) – 종목코드 (6자리)

  • +
  • quantity (int) – 주문수량

  • +
  • price (int) – 주문단가

  • +
  • quote_type (str) – 거래구분 (혹은 호가구분)

  • +
  • original_order_no (str) – 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다.

  • +
+
+
+
+ +
+
+RealCall(self, scrno, codes, fids, opt_type=None, infer_fids=False, readable_names=False, fast_parse=False)[source]
+

실시간 데이터 요청에 해당하는 RPC 입니다.

+

SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 +직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 +추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. +해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다.

+

해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 +클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. +이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다.

+
+ +
+
+LoadConditionCall(self)[source]
+

조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다.

+

GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+ConditionCall(self, scrno, condition_name, condition_index, search_type, with_info=False, is_future_option=False, request_name=None)[source]
+

조건검색 기능에 해당하는 RPC 입니다.

+

SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 +처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+SetLogLevel(self, level, logger='')[source]
+

서버에 존재하는 특정 로거의 로그레벨을 설정합니다.

+
+ +
+
+LoadCondition(self)[source]
+

조건검색 관련 조건식을 불러옵니다.

+
+ +
+
+IsConditionLoaded(self)[source]
+

조건식이 로드 되었는지 여부를 반환합니다.

+
+ +
+
+EnsureConditionLoaded(self, force=False)[source]
+

조건식이 로드됨을 보장하도록 합니다.

+

이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. +조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다.

+
+ +
+
+RateLimitedCommRqData(self, rqname, trcode, prevnext, scrno, inputs=None)[source]
+

CommRqData() 와 동일하지만 호출제한 회피를 위한 함수입니다. +필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다.

+
+ +
+
+RateLimitedSendCondition(self, scrno, condition_name, condition_index, search_type)[source]
+

SendCondition() 과 동일하지만 호출제한 회피를 위한 함수입니다. +필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다.

+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubExtendedWrapper(stub, executor)[source]
+

Bases: KiwoomOpenApiPlusServiceClientStubCoreWrapper, koapy.utils.logging.Logging.Logging

+

제공되는 RPC 들을 활용한 여러 사용 케이스들을 구현합니다.

+
+
+GetStockBasicInfoAsDict(self, code, rqname=None, scrno=None)[source]
+

주식 종목의 기본정보를 딕셔너리 형태로 반환합니다.

+

TR: OPT10001

+
+ +
+
+GetStockBasicInfoAsSeries(self, code, rqname=None, scrno=None)[source]
+

주식 종목의 기본정보를 pd.Series 형태로 반환합니다.

+

TR: OPT10001

+
+ +
+
+GetStockQuoteInfoAsDataFrame(self, codes=None, rqname=None, scrno=None)[source]
+

복수개의 주식 종목들의 기본정보를 pd.DataFrame 형태로 반환합니다.

+

TR: OPTKWFID

+
+ +
+
+GetTickStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

틱 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10079

+
+ +
+
+GetMinuteStockDataAsDataFrame(self, code, interval, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

분 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10080

+
+ +
+
+GetDailyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

일 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10081

+
+ +
+
+GetWeeklyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

주 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10082

+
+ +
+
+GetMonthlyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

월 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10083

+
+ +
+
+GetYearlyStockDataAsDataFrame(self, code, start_date=None, end_date=None, include_end=False, adjusted_price=False, rqname=None, scrno=None)[source]
+

년 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다.

+

TR: OPT10094

+
+ +
+
+GetDepositInfo(self, account_no, lookup_type=None, with_multi=False, rqname=None, scrno=None)[source]
+

계좌의 예수금 정보를 반환합니다.

+

TR: OPW00001

+

조회구분 = 3:추정조회, 2:일반조회

+
+ +
+
+GetStockQuotes(self, code, rqname=None, scrno=None)[source]
+

주식의 호가정보를 반환합니다.

+

TR: OPT10004

+
+ +
+
+GetOrderLogAsDataFrame1(self, account_no, order_type=None, status_type=None, code=None, rqname=None, scrno=None)[source]
+

미체결 주문 정보를 반환합니다.

+

TR: OPT10075

+

계좌번호 = 전문 조회할 보유계좌번호 +전체종목구분 = 0:전체, 1:종목 +매매구분 = 0:전체, 1:매도, 2:매수 +종목코드 = 전문 조회할 종목코드 +체결구분 = 0:전체, 2:체결, 1:미체결

+
+ +
+
+GetOrderLogAsDataFrame2(self, account_no, order_type=None, status_type=None, code=None, order_no=None, rqname=None, scrno=None)[source]
+

주문 체결 정보를 반환합니다.

+

TR: OPT10076

+

종목코드 = 전문 조회할 종목코드 +조회구분 = 0:전체, 1:종목 +매도수구분 = 0:전체, 1:매도, 2:매수 +계좌번호 = 전문 조회할 보유계좌번호 +비밀번호 = 사용안함(공백) +주문번호 = 조회할 주문번호 +체결구분 = 0:전체, 2:체결, 1:미체결

+
+ +
+
+GetOrderLogAsDataFrame3(self, account_no, date=None, sort_type=None, asset_type=None, order_type=None, code=None, starting_order_no=None, rqname=None, scrno=None)[source]
+

계좌별 주문 체결 내역을 반환합니다.

+

TR: OPW00007

+

주문일자 = YYYYMMDD (20170101 연도4자리, 월 2자리, 일 2자리 형식) +계좌번호 = 전문 조회할 보유계좌번호 +비밀번호 = 사용안함(공백) +비밀번호입력매체구분 = 00 +조회구분 = 1:주문순, 2:역순, 3:미체결, 4:체결내역만 +주식채권구분 = 0:전체, 1:주식, 2:채권 +매도수구분 = 0:전체, 1:매도, 2:매수 +종목코드 +시작주문번호

+
+ +
+
+GetAccountRateOfReturnAsDataFrame(self, account_no, rqname=None, scrno=None)[source]
+

계좌별 수익률 정보를 반환합니다.

+

TR: OPT10085

+
+ +
+
+GetAccountEvaluationStatusAsSeriesAndDataFrame(self, account_no, include_delisted=True, rqname=None, scrno=None)[source]
+

계좌의 평가 현황 정보를 반환합니다.

+

TR: OPW00004

+
+ +
+
+GetAccountExecutionBalanceAsSeriesAndDataFrame(self, account_no, rqname=None, scrno=None)[source]
+

계좌의 체결 잔고 정보를 반환합니다.

+

TR: OPW00005

+

모의투자에서는 지원하지 않는 TR 입니다.

+
+ +
+
+GetAccountEvaluationBalanceAsSeriesAndDataFrame(self, account_no, lookup_type=None, rqname=None, scrno=None)[source]
+

계좌의 평가 잔고 내역 정보를 반환합니다.

+

TR: OPW00018

+

조회구분 = 1:합산, 2:개별

+

[ 주의 ] +“수익률%” 데이터는 모의투자에서는 소숫점표현, 실거래서버에서는 소숫점으로 변환 필요 합니다.

+
+ +
+
+GetMarketPriceInfo(self, code, rqname=None, scrno=None)[source]
+

종목의 시세표성 정보를 반환합니다.

+

TR: OPT10007

+
+ +
+
+GetRealDataForCodesAsStream(self, codes, fids=None, opt_type=None, screen_no=None, infer_fids=False, readable_names=False, fast_parse=False)[source]
+

실시간 데이터를 요청하고 스트림 형태로 반환받습니다.

+
+ +
+
+GetCodeListByCondition(self, condition_name, condition_index=None, with_info=False, is_future_option=False, request_name=None, screen_no=None)[source]
+

주어진 조건식으로 조건검색을 수행하고 +검색된 종목의 종목코드를 리스트로 반환받습니다.

+

파라미터 중 with_info 가 True 로 설정된 경우, +검색된 종목들에 대한 기본 정보도 추가로 같이 반환됩니다.

+
+ +
+
+GetCodeListByConditionAsStream(self, condition_name, condition_index=None, with_info=False, is_future_option=False, request_name=None, screen_no=None, old_behavior=False)[source]
+

주어진 조건식을 실시간 조건검색으로 등록합니다. +이후 발생하는 이벤트들을 스트림 형태로 제공합니다.

+

최초 검색결과는 OnReceiveTrCondition() 이벤트로 반환되며 +이후 종목의 추가/제외는 OnReceiveRealCondition() 이벤트로 반환됩니다.

+

만약 with_info 가 True 로 설정된 경우, +검색된 종목마다 추가적인 정보가 OnReceiveTrData() 이벤트를 통해 반환됩니다.

+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubWrapper(stub, executor)[source]
+

Bases: KiwoomOpenApiPlusServiceClientStubExtendedWrapper

+

KiwoomOpenApiPlusServiceClientStubCoreWrapper, KiwoomOpenApiPlusServiceClientStubExtendedWrapper 의 구현 및 +KiwoomOpenApiPlusQAxWidgetUniversalMixin 의 구현들까지 최종적으로 포함된 +KiwoomOpenApiPlusServiceClientStub 객체를 위한 Mixin 래퍼 클래스 입니다.

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.html new file mode 100644 index 00000000..a7945400 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.html @@ -0,0 +1,193 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + +

convert_arguments_from_protobuf_to_python(arguments)

convert_arguments_from_python_to_protobuf(arguments, arguments_message)

+
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils.convert_arguments_from_protobuf_to_python(arguments)[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils.convert_arguments_from_python_to_protobuf(arguments, arguments_message)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.html new file mode 100644 index 00000000..e7245be5 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.html @@ -0,0 +1,221 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusServiceServer

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer.KiwoomOpenApiPlusServiceServer(control, host=None, port=None, credentials=None, **kwargs)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+reinitialize_server(self)[source]
+
+ +
+
+get_host(self)[source]
+
+ +
+
+get_port(self)[source]
+
+ +
+
+start(self)[source]
+
+ +
+
+wait_for_termination(self, timeout=None)[source]
+
+ +
+
+is_running(self)[source]
+
+ +
+
+stop(self, grace=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.html new file mode 100644 index 00000000..361396e6 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.html @@ -0,0 +1,342 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusServiceServicer

KiwoomOpenApiPlusService RPC 의 구현체 입니다.

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer.KiwoomOpenApiPlusServiceServicer(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer

+

KiwoomOpenApiPlusService RPC 의 구현체 입니다.

+
+
+property control(self)[source]
+
+ +
+
+property screen_manager(self)[source]
+
+ +
+
+Call(self, request, context)[source]
+

임의의 함수 호출을 위한 RPC 입니다.

+

함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 +호출결과를 응답 메시지를 통해 전달합니다.

+

함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다.

+
+ +
+
+Listen(self, request, context)[source]
+

단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다.

+

전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. +이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다.

+

서버측의 이벤트 핸들러 함수는 해당 이벤트를 클라이언트에 전송한 이후 즉시 종료됩니다.

+
+ +
+
+BidirectionalListen(self, request_iterator, context)[source]
+

단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다.

+

전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. +이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다.

+

앞선 Listen() RPC 와 다르게 해당 RPC 는 이벤트 발생시 서버측에서는 이벤트 내용을 응답 메시지로 전달한 다음 +다시 클라이언트 측에서 ACK 요청을 줄 때 까지 서버측 이벤트 핸들러 함수 내에서 대기합니다. +따라서 클라이언트는 서버측 이벤트 핸들러 함수 컨텍스트 내에서 이벤트를 처리할 수 있고 +처리를 완료하면 다시 서버측으로 ACK 요청을 보내 서버측 이벤트 핸들러가 완료될 수 있도록 해야 합니다.

+
+ +
+
+LoginCall(self, request, context)[source]
+

키움증권 서버 연결 시나리오에 해당하는 RPC 입니다.

+

CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+TransactionCall(self, request, context)[source]
+

TR 요청에 해당하는 RPC 입니다.

+

CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 +추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. +해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다.

+

경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 +추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다.

+

일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 +내부적으로 호출됩니다.

+

서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 +대기시간이 발생할 수 있습니다.

+

최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. +몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, +TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다.

+
+ +
+
+OrderCall(self, request, context)[source]
+

주문 요청에 해당하는 RPC 입니다.

+

SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 +주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다.

+

일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. +다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다.

+

이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다.

+

기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다.

+
+ +
+
+RealCall(self, request, context)[source]
+

실시간 데이터 요청에 해당하는 RPC 입니다.

+

SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+

OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 +직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 +추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. +해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다.

+

해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 +클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. +이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다.

+
+ +
+
+LoadConditionCall(self, request, context)[source]
+

조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다.

+

GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 +클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+ConditionCall(self, request, context)[source]
+

조건검색 기능에 해당하는 RPC 입니다.

+

SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 +처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다.

+
+ +
+
+BidirectionalRealCall(self, request_iterator, context)[source]
+

실시간 데이터 요청에 해당하는 RPC 입니다.

+

기존의 RealCall() RPC 는 최초 실시간 데이터 등록 이후 이벤트를 듣는 것만 가능했다면 +새로운 BidirectionalRealCall() 에서는 최초 설정된 이벤트 스트림을 계속 유지하면서 +신규 실시간 데이터 등록 혹은 해지를 추가로 요청해 반영할 수 있습니다.

+
+ +
+
+OrderListen(self, request, context)[source]
+

주문 이벤트를 듣고 싶을때 사용할 수 있는 RPC 입니다.

+

기존의 OrderCall() RPC 는 특정 주문을 수행하고 해당 주문과 관련된 이벤트들만 반환했다면 +해당 RPC 는 특정 주문 수행 없이 모든 주문관련 이벤트를 듣고 싶을때 사용할 수 있습니다.

+
+ +
+
+CustomListen(self, request, context)[source]
+

이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다.

+

해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, +클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다.

+

내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다.

+
+ +
+
+CustomCallAndListen(self, request, context)[source]
+

이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다.

+

앞선 CustomListen() 과의 차이점은 요청시 특정 함수를 최초 1회 호출하고 이후 들어오는 이벤트를 처리한다는 점입니다.

+

해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, +클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다.

+

내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다.

+
+ +
+
+SetLogLevel(self, request, context)[source]
+

서버에 존재하는 특정 로거의 로그레벨을 설정합니다.

+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.html new file mode 100644 index 00000000..96cd1c45 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.html @@ -0,0 +1,587 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2

+

Generated protocol buffer code.

+
+

Module Contents

+
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.DESCRIPTOR[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.LESS_THAN_OR_EQUAL_TO = 0[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.LESS_THAN = 1[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.GREATER_THAN_OR_EQUAL_TO = 2[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.GREATER_THAN = 3[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.EQUAL_TO = 4[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.NOT_EQUAL_TO = 5[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.enum_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.message_type[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.containing_oneof[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.Argument[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.CallRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.ReturnValue[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.CallResponse[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.ListenRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.HandledRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.StopListenRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.SingleData[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.RepeatedString[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.MultiData[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.ListenResponse[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.CallAndListenRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.CallAndListenResponse[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.LoginCredentials[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.LoginRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.RealRequestFlags[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.RealRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.TransactionStopCondition[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.TransactionRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.OrderSubscriptionTarget[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.OrderRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.LoadConditionRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.ConditionRequestFlags[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.ConditionRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.SetLogLevelRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.SetLogLevelResponse[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalRealInitializeRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalRealRegisterRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalRealRemoveRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalRealStopRequest[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2.BidirectionalRealRequest[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.html new file mode 100644 index 00000000..7b387c66 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.html @@ -0,0 +1,426 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc

+

Client and server classes corresponding to protobuf-defined services.

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusServiceStub

Missing associated documentation comment in .proto file.

KiwoomOpenApiPlusServiceServicer

Missing associated documentation comment in .proto file.

KiwoomOpenApiPlusService

Missing associated documentation comment in .proto file.

+
+
+

Functions

+ ++++ + + + + + +

add_KiwoomOpenApiPlusServiceServicer_to_server(servicer, server)

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceStub(channel)[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+
+Call(self, request, context)[source]
+
    +
  1. rpcs for general function calls

  2. +
+

unary rpc for an arbitrary function call, +can invoke arbitrary function on the server side by giving its name and arguments, +currently only simple data types like str and int are supported for arguments and return values

+
+ +
+
+Listen(self, request, context)[source]
+
    +
  1. rpcs for listening and handling events

  2. +
+

server streaming rpc usually for listening events, +server will simply send stream items to client whenever event that is being listened is triggered, +client can handle those events solely on its own on client side but there is no guarantee that it will be synced with the server, +which means that event handler on the server side will not wait for the client to finish handling each event

+
+ +
+
+BidirectionalListen(self, request_iterator, context)[source]
+

bidirectional streaming rpc usually for listening and handling events with proper callbacks, +server will send an stream item to client whenever an event is triggered and will wait for an client’s ack, +so that following callbacks from the client can actually be processed inside the server’s event handler context

+
+ +
+
+LoginCall(self, request, context)[source]
+
    +
  1. rpcs for simple use cases that can be categorized into serveral distinct usage patterns

  2. +
+

server streaming rpc for login/connect scenario, +would invoke Connect() and wait for OnEventConnect() event to test its success

+
+ +
+
+TransactionCall(self, request, context)[source]
+

server streaming rpc for general transaction requests, +would invoke CommRqData() with several SetInputValue()s for a transaction request, +would wait for OnReceiveTrData() events, +would handle those events to gather results by invoking GetRepeatCnt() and GetCommData() inside, +might do additional CommRqData() and SetInputValue() inside event handler for possible consecutive lookups

+
+ +
+
+OrderCall(self, request, context)[source]
+

server streaming rpc for making orders (buy/sell + update/cancel), +would invoke SendOrder() for submitting an order, +would wait for OnReceiveTrData() and OnReceiveChejanData() events to track its progress

+
+ +
+
+RealCall(self, request, context)[source]
+

server streaming rpc for listening realtime data events, +certain transaction requests would also register some realtime data to be sent, +but usually would just call SetRealReg() to register desired realtime data to listen explicitly, +and would call SetRealRemove() to unregister them after done using, +would wait for OnReceiveRealData() events

+
+ +
+
+LoadConditionCall(self, request, context)[source]
+

server streaming rpc for loading condition settings for conditioned search, +would call GetConditionLoad() and wait for OnReceiveConditionVer() event to test its success

+
+ +
+
+ConditionCall(self, request, context)[source]
+

server streaming rpc for conditioned search (serching stocks with serveral conditions), +would call SendCondition() and wait for OnReceiveTrCondition() or OnReceiveRealCondition() based on its requested type

+
+ +
+
+BidirectionalRealCall(self, request_iterator, context)[source]
+
    +
  1. rpcs for more complex use cases based on the previously categorized simple cases above

  2. +
+

bidirectional streaming rpc for listening realtime data events, +with capability of managing observation pool (what stocks, what fields to listen to) online, +those management requests would be sent over the client streaming line, +and ordinary realtime data events would be sent over the server streaming line

+
+ +
+
+OrderListen(self, request, context)[source]
+

server streaming rpc for just listening order events (without submiting any order request compared to the simple case), +this is one-sided streaming rpc (server streaming rpc) like Listen() rpc, +so server would just send stream items with no consideration on coordination with its client

+
+ +
+
+CustomListen(self, request, context)[source]
+
    +
  1. rpcs for customized usage scenario (when there is no proper predefined interface to utilize)

  2. +
+

pretty much similar to server streaming Listen() rpc, +but event handler would be instantiated dynamically based on the code given through the request

+
+ +
+
+CustomCallAndListen(self, request, context)[source]
+

pretty much similar to server streaming XXXCall() rpcs (or even Call() rpc), +but event handler would be instantiated dynamically based on the code given through the request

+
+ +
+
+SetLogLevel(self, request, context)[source]
+
    +
  1. rpcs for other mics scenarios

  2. +
+

would update log level of process that this grpc server lives

+
+ +
+ +
+
+koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.add_KiwoomOpenApiPlusServiceServicer_to_server(servicer, server)[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusService[source]
+

Bases: object

+

Missing associated documentation comment in .proto file.

+
+
+static Call(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static Listen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static BidirectionalListen(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static LoginCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static TransactionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static OrderCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static RealCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static LoadConditionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static ConditionCall(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static BidirectionalRealCall(request_iterator, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static OrderListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static CustomListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static CustomCallAndListen(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+
+static SetLogLevel(request, target, options=(), channel_credentials=None, call_credentials=None, insecure=False, compression=None, wait_for_ready=None, timeout=None, metadata=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.html new file mode 100644 index 00000000..bf2adeb0 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusConditionEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler.KiwoomOpenApiPlusConditionEventHandler(control, request, context, screen_manager)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.html new file mode 100644 index 00000000..5aa8b640 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.html @@ -0,0 +1,193 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusEventHandlerForGrpc

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc(control, context)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler

+
+
+property context(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.html new file mode 100644 index 00000000..35ad3fe2 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.html @@ -0,0 +1,377 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + +

KiwoomOpenApiPlusLazyAllEventHandler

KiwoomOpenApiPlusEagerAllEventHandler

KiwoomOpenApiPlusAllEventHandler

KiwoomOpenApiPlusLazySomeEventHandler

KiwoomOpenApiPlusEagerSomeEventHandler

KiwoomOpenApiPlusSomeEventHandler

KiwoomOpenApiPlusSomeBidirectionalEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazyAllEventHandler(control, context)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerAllEventHandler(control, context)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusAllEventHandler(control, context)[source]
+

Bases: KiwoomOpenApiPlusEagerAllEventHandler

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazySomeEventHandler(control, request, context)[source]
+

Bases: KiwoomOpenApiPlusLazyAllEventHandler

+
+
+slots(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerSomeEventHandler(control, request, context)[source]
+

Bases: KiwoomOpenApiPlusEagerAllEventHandler

+
+
+slots(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusSomeEventHandler(control, request, context)[source]
+

Bases: KiwoomOpenApiPlusEagerSomeEventHandler

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusSomeBidirectionalEventHandler(control, request_iterator, context)[source]
+

Bases: KiwoomOpenApiPlusLazySomeEventHandler

+
+
+await_handled(self)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.html new file mode 100644 index 00000000..bc31c767 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusKwTrEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler.KiwoomOpenApiPlusKwTrEventHandler(control, request, context, screen_manager)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.html new file mode 100644 index 00000000..72db0767 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.html @@ -0,0 +1,198 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusLoadConditionEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler.KiwoomOpenApiPlusLoadConditionEventHandler(control, context, request)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.html new file mode 100644 index 00000000..4ef3998f --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.html @@ -0,0 +1,240 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusLoggingEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler, koapy.utils.logging.Logging.Logging

+
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, _datalength, _errorcode, _message, _splmmsg)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+

[OnReceiveMsg()이벤트]

+
+

OnReceiveMsg( +BSTR sScrNo, // 화면번호 +BSTR sRQName, // 사용자 구분명 +BSTR sTrCode, // TR이름 +BSTR sMsg // 서버에서 전달하는 메시지 +)

+

서버통신 후 수신한 메시지를 알려줍니다. +메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 +이 코드번호로 분류하시면 안됩니다.

+
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveRealCondition(self, code, condition_type, condition_name, condition_index)[source]
+
+ +
+
+OnReceiveTrCondition(self, scrnno, codelist, condition_name, condition_index, prevnext)[source]
+
+ +
+
+OnReceiveConditionVer(self, ret, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.html new file mode 100644 index 00000000..0658e97e --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.html @@ -0,0 +1,198 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusLoginEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler.KiwoomOpenApiPlusLoginEventHandler(control, request, context)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc

+
+
+on_enter(self)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.html new file mode 100644 index 00000000..4bb0e79f --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.html @@ -0,0 +1,261 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusBaseOrderEventHandler

KiwoomOpenApiPlusAllOrderEventHandler

KiwoomOpenApiPlusOrderEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusBaseOrderEventHandler(control, context)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+ResponseForOnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+ResponseForOnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+ResponseForOnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusAllOrderEventHandler(control, context)[source]
+

Bases: KiwoomOpenApiPlusBaseOrderEventHandler

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusOrderEventHandler(control, request, context, screen_manager)[source]
+

Bases: KiwoomOpenApiPlusBaseOrderEventHandler, koapy.utils.logging.Logging.Logging

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.html new file mode 100644 index 00000000..ccd5b816 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.html @@ -0,0 +1,262 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

KiwoomOpenApiPlusRealEventHandler

KiwoomOpenApiPlusBidirectionalRealEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusRealEventHandler(control, request, context, screen_manager)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusBidirectionalRealEventHandler(control, request_iterator, context, screen_manager)[source]
+

Bases: KiwoomOpenApiPlusRealEventHandler, koapy.utils.logging.Logging.Logging

+
+
+register_code(self, code, fid_list=None)[source]
+
+ +
+
+remove_code(self, code)[source]
+
+ +
+
+remove_all_codes(self)[source]
+
+ +
+
+remove_all_screens(self)[source]
+
+ +
+
+consume_request_iterator(self)[source]
+
+ +
+
+stop_request_iterator_consumer(self)[source]
+
+ +
+
+start_request_iterator_consumer(self)[source]
+
+ +
+
+on_enter(self)[source]
+
+ +
+
+on_exit(self, exc_type=None, exc_value=None, traceback=None)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.html new file mode 100644 index 00000000..01e43d2f --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusTrEventHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler.KiwoomOpenApiPlusTrEventHandler(control, request, context, screen_manager)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc, koapy.utils.logging.Logging.Logging

+
+
+on_enter(self)[source]
+
+ +
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.html new file mode 100644 index 00000000..a4e5a6a6 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.html @@ -0,0 +1,180 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.event — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.html new file mode 100644 index 00000000..4696880b --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc

+
+

Subpackages

+ +
+
+

Submodules

+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.html new file mode 100644 index 00000000..5dbc5a3c --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

compile_proto()

+
+
+koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto.compile_proto()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.html new file mode 100644 index 00000000..14d53fb4 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.html @@ -0,0 +1,171 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.grpc.tools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/index.html new file mode 100644 index 00000000..d058404f --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/index.html @@ -0,0 +1,253 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus

+
+

Subpackages

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.html new file mode 100644 index 00000000..6082a219 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.html @@ -0,0 +1,258 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

DialogToHandle

KiwoomOpenApiPlusDialogToHandle

KiwoomOpenApiPlusDialogHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.DialogToHandle[source]
+
+
+should_handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) → bool[source]
+
+ +
+
+handle(self, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+
+handle_if_needed(self, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogToHandle(title: Optional[str] = None, time: Optional[datetime.time] = None, body: Optional[str] = None, app: Optional[koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication] = None, restart_type: Optional[koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.RestartType] = None)[source]
+

Bases: DialogToHandle, koapy.utils.logging.Logging.Logging

+
+
+classmethod should_handle_by_title(cls, dialog: koapy.compat.pywinauto.WindowSpecification, title: str)[source]
+
+ +
+
+classmethod handle_by_clicking_button(cls, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+
+classmethod handle_by_emiting_should_restart_signal(cls, app: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication, restart_type: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.RestartType)[source]
+
+ +
+
+to_specification(self) → koapy.compat.pywinauto.WindowSpecification[source]
+
+ +
+
+should_handle(self, dialog: koapy.compat.pywinauto.WindowSpecification) → bool[source]
+
+ +
+
+handle(self, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+
+handle_if_needed(self, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogHandler(app: koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler.QDialogHandler

+
+
+onReadyDialog(self, dialog: koapy.compat.pywinauto.WindowSpecification)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.html new file mode 100644 index 00000000..cf996214 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.html @@ -0,0 +1,361 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + +

KiwoomOpenApiPlusManagerApplicationArgumentParser

KiwoomOpenApiPlusServerApplicationProcess

KiwoomOpenApiPlusServerApplicationSubprocess

KiwoomOpenApiPlusManagerApplication

+
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplicationArgumentParser[source]
+

Bases: koapy.cli.extensions.parser.ArgumentParser

+
+
+parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → argparse.Namespace[source]
+
+ +
+
+parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → Tuple[argparse.Namespace, List[str]][source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusServerApplicationProcess(args, parent=None)[source]
+

Bases: koapy.compat.pyside2.QtCore.QProcess

+
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusServerApplicationSubprocess(args, parent=None)[source]
+
+
+start(self)[source]
+
+ +
+
+waitForStarted(self, msecs: int = 30000) → bool[source]
+
+ +
+
+close(self)[source]
+
+ +
+
+waitForFinished(self, msecs: int = 30000) → bool[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication(args=())[source]
+

Bases: koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging

+
+
+class ConnectionStatus[source]
+

Bases: enum.Enum

+

Generic enumeration.

+

Derive from this class to define new enumerations.

+
+
+DISCONNECTED = 1[source]
+
+ +
+
+CONNECTED = 2[source]
+
+ +
+ +
+
+class ServerType[source]
+

Bases: enum.Enum

+

Generic enumeration.

+

Derive from this class to define new enumerations.

+
+
+SIMULATION = 1[source]
+
+ +
+
+REAL = 2[source]
+
+ +
+
+UNKNOWN = 3[source]
+
+ +
+ +
+
+class RestartType[source]
+

Bases: enum.Enum

+

Generic enumeration.

+

Derive from this class to define new enumerations.

+
+
+NO_RESTART = 1[source]
+
+ +
+
+RESTART_ONLY = 2[source]
+
+ +
+
+RESTART_AND_RESTORE = 3[source]
+
+ +
+
+RESTART_AND_CONNECT = 4[source]
+
+ +
+
+RESTART_WITH_UPDATE = 5[source]
+
+ +
+
+RESTART_WITH_UPDATE_AND_RESTORE = 6[source]
+
+ +
+
+RESTART_WITH_UPDATE_AND_CONNECT = 7[source]
+
+ +
+ +
+
+shouldRestart[source]
+
+ +
+
+close(self)[source]
+
+ +
+
+exec_(self)[source]
+
+ +
+
+exit(self, return_code=0)[source]
+
+ +
+
+restart(self, restart_type: Optional[RestartType] = None)[source]
+
+ +
+
+execAndExit(self)[source]
+
+ +
+
+classmethod main(cls, args=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.html new file mode 100644 index 00000000..2501b0a2 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.html @@ -0,0 +1,266 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

KiwoomOpenApiPlusServerApplicationArgumentParser

KiwoomOpenApiPlusServerApplication

+
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplicationArgumentParser[source]
+

Bases: koapy.cli.extensions.parser.ArgumentParser

+
+
+parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → argparse.Namespace[source]
+
+ +
+
+parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → Tuple[argparse.Namespace, List[str]][source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplication(args=())[source]
+

Bases: koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging

+
+
+class ConnectionStatus[source]
+

Bases: enum.Enum

+

Generic enumeration.

+

Derive from this class to define new enumerations.

+
+
+DISCONNECTED = 1[source]
+
+ +
+
+CONNECTED = 2[source]
+
+ +
+ +
+
+class ServerType[source]
+

Bases: enum.Enum

+

Generic enumeration.

+

Derive from this class to define new enumerations.

+
+
+SIMULATION = 1[source]
+
+ +
+
+REAL = 2[source]
+
+ +
+
+UNKNOWN = 3[source]
+
+ +
+ +
+
+exec_(self)[source]
+
+ +
+
+exit(self, return_code=0)[source]
+
+ +
+
+execAndExit(self)[source]
+
+ +
+
+classmethod main(cls, args=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.html new file mode 100644 index 00000000..9c141be6 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.html @@ -0,0 +1,186 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiPlusSignalHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler.KiwoomOpenApiPlusSignalHandler(app, parent=None)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler.QSignalHandler

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.html new file mode 100644 index 00000000..64b77032 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.html @@ -0,0 +1,172 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.html new file mode 100644 index 00000000..ebabcb8a --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.html @@ -0,0 +1,193 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

PipeableMultiThreadedRendezvous

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous.PipeableMultiThreadedRendezvous(rendezvous, iterator=None)[source]
+

Bases: collections.abc.Iterator

+
+
+pipe(self, func)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.html new file mode 100644 index 00000000..1943c070 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.html @@ -0,0 +1,171 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.html new file mode 100644 index 00000000..dcc721c3 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.html @@ -0,0 +1,193 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.html new file mode 100644 index 00000000..19eef1bf --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.list_conversion — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.list_conversion

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

string_to_list(s, sep=';')

list_to_string(l, sep=';')

convert_list_arguments(*indices)

+
+
+koapy.backend.kiwoom_open_api_plus.utils.list_conversion.string_to_list(s, sep=';')[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.utils.list_conversion.list_to_string(l, sep=';')[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_plus.utils.list_conversion.convert_list_arguments(*indices)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.html new file mode 100644 index 00000000..47d7740f --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.module_path — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.module_path

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

GetAPIModulePath() → pathlib.Path

+
+
+koapy.backend.kiwoom_open_api_plus.utils.module_path.GetAPIModulePath() → pathlib.Path[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.html new file mode 100644 index 00000000..de1becbf --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.html @@ -0,0 +1,223 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

QDialogHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler.QDialogHandler(specifications: Optional[Sequence[koapy.compat.pywinauto.WindowSpecification]] = None, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None)[source]
+

Bases: koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging

+
+
+readyDialog[source]
+
+ +
+
+notReadyDialog[source]
+
+ +
+
+classmethod from_titles(cls, titles: Sequence[str], allow_magic_lookup: bool = False)[source]
+
+ +
+
+get_text_of_dialog(self, dialog: koapy.compat.pywinauto.WindowSpecification, default: Optional[str] = None)[source]
+
+ +
+
+run(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+wait_for_termination(self, timeout=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.html new file mode 100644 index 00000000..087bbae8 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.html @@ -0,0 +1,238 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

QSignalHandler

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler.QSignalHandler(signals: Iterable[signal.Signals], parent: Optional[koapy.compat.pyside2.QtCore.QObject])           QSignalHandler(parent: Optional[koapy.compat.pyside2.QtCore.QObject])[source]
+

Bases: koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLogging

+
+
+signaled[source]
+
+ +
+
+onReadyRead(self)[source]
+
+ +
+
+emitSignal(self, signal, frame)[source]
+
+ +
+
+setWakeUpFileDescriptor(self, descriptor, warn_on_full_buffer=True)[source]
+
+ +
+
+restoreWakeUpFileDescrptor(self)[source]
+
+ +
+
+setHandler(self, signal, handler)[source]
+
+ +
+
+restoreHandler(self, signal, default=None)[source]
+
+ +
+
+restoreAllHandlers(self)[source]
+
+ +
+
+setAll(self)[source]
+
+ +
+
+restoreAll(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.html new file mode 100644 index 00000000..1ed98d67 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.html @@ -0,0 +1,239 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QThreadPoolExecutorRunnable

QThreadPoolExecutor

This is an abstract base class for concrete asynchronous executors.

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutorRunnable(future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Union[Tuple[Any], List[Any]], kwargs: Dict[str, Any])[source]
+

Bases: koapy.compat.pyside2.QtCore.QRunnable

+
+
+run(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutor(thread_pool: koapy.compat.pyside2.QtCore.QThreadPool, parent: Optional[koapy.compat.pyside2.QtCore.QObject])           QThreadPoolExecutor(parent: Optional[koapy.compat.pyside2.QtCore.QObject])[source]
+

Bases: koapy.compat.pyside2.QtCore.QObject, concurrent.futures.Executor

+

This is an abstract base class for concrete asynchronous executors.

+
+
+submit(self, fn, *args, **kwargs)[source]
+

Submits a callable to be executed with the given arguments.

+

Schedules the callable to be executed as fn(*args, **kwargs) and returns +a Future instance representing the execution of the callable.

+
+

System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst, line 39); backlink

+

Inline emphasis start-string without end-string.

+
+
+

System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst, line 39); backlink

+

Inline strong start-string without end-string.

+
+
+
Returns
+

A Future representing the given call.

+
+
+
+ +
+
+shutdown(self, wait=True, cancel_futures=False)[source]
+

Clean-up the resources associated with the Executor.

+

It is safe to call this method several times. Otherwise, no other +methods can be called after this one.

+
+
Parameters
+

wait – If True then shutdown will not return until all running +futures have finished executing and the resources used by the +executor have been reclaimed.

+
+
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.html new file mode 100644 index 00000000..6954e6eb --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.html @@ -0,0 +1,173 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.html new file mode 100644 index 00000000..733f1f78 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.html @@ -0,0 +1,193 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

QueueBasedBufferedIterator

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator.QueueBasedBufferedIterator(iterator, queue=None, maxsize=None)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator, koapy.utils.logging.Logging.Logging

+
+
+next(self, block=True, timeout=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.html new file mode 100644 index 00000000..ac4958dc --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.html @@ -0,0 +1,248 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QueueBasedIterableObserverIterator

QueueBasedIterableObserver

Observer abstract base class

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserverIterator(queue, sentinel)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator

+
+
+next(self, block=True, timeout=None)[source]
+
+ +
+
+head(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserver(queue=None, maxsize=None)[source]
+

Bases: rx.core.typing.Observer

+

Observer abstract base class

+

An Observer is the entity that receives all emissions of a subscribed +Observable.

+
+
+property queue(self)[source]
+
+ +
+
+on_next(self, value)[source]
+

Notifies the observer of a new element in the sequence.

+
+
Parameters
+

value – The received element.

+
+
+
+ +
+
+on_error(self, error)[source]
+

Notifies the observer that an exception has occurred.

+
+
Parameters
+

error – The error that has occurred.

+
+
+
+ +
+
+on_completed(self)[source]
+

Notifies the observer of the end of the sequence.

+
+ +
+
+stop(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.html new file mode 100644 index 00000000..95b1e851 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.html @@ -0,0 +1,241 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QueueIterator

BufferedQueueIterator

+
+
+class koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.QueueIterator(queue)[source]
+
+
+property queue(self)[source]
+
+ +
+
+next(self, block=True, timeout=None)[source]
+
+ +
+
+next_nowait(self)[source]
+
+ +
+
+has_next(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+enable(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator(queue)[source]
+

Bases: QueueIterator

+
+
+next(self, block=True, timeout=None)[source]
+
+ +
+
+has_next(self)[source]
+
+ +
+
+head(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.html b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.html new file mode 100644 index 00000000..18fc2e11 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.html @@ -0,0 +1,173 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_plus.utils.queue — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.html new file mode 100644 index 00000000..5cc91486 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.html @@ -0,0 +1,190 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWDynamicCallable

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable.KiwoomOpenApiWDynamicCallable(control, name)[source]
+
+
+is_valid_return_type(self, result)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.html new file mode 100644 index 00000000..179e127d --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.html @@ -0,0 +1,163 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEntrypoint — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.html new file mode 100644 index 00000000..2d64bae8 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.html @@ -0,0 +1,412 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError

+
+

Module Contents

+
+
+exception koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWError(message=None)[source]
+

Bases: Exception

+

Common base class for all non-exit exceptions.

+
+
+property message(self)[source]
+
+ +
+
+classmethod try_or_raise(cls, arg, message=None)[source]
+
+ +
+
+classmethod try_or_raise_boolean(cls, arg, message)[source]
+
+ +
+ +
+
+exception koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWNegativeReturnCodeError(code, message=None)[source]
+

Bases: KiwoomOpenApiWError

+

Common base class for all non-exit exceptions.

+
+
+OP_ERR_NONE = 0[source]
+
+ +
+
+OP_ERR_NO_LOGIN[source]
+
+ +
+
+OP_ERR_LOGIN[source]
+
+ +
+
+OP_ERR_CONNECT[source]
+
+ +
+
+OP_ERR_VERSION[source]
+
+ +
+
+OP_ERR_TRCODE[source]
+
+ +
+
+OP_ERR_NO_REGOPENAPI[source]
+
+ +
+
+OP_ERR_SISE_OVERFLOW[source]
+
+ +
+
+OP_ERR_ORDER_OVERFLOW[source]
+
+ +
+
+OP_ERR_RQ_WRONG_INPUT[source]
+
+ +
+
+OP_ERR_ORD_WRONG_INPUT[source]
+
+ +
+
+OP_ERR_ORD_WRONG_ACCPWD[source]
+
+ +
+
+OP_ERR_ORD_WRONG_ACCNO[source]
+
+ +
+
+OP_ERR_ORD_WRONG_QTY200[source]
+
+ +
+
+OP_ERR_ORD_WRONG_QTY400[source]
+
+ +
+
+MSG_ERR_NONE = 정상처리[source]
+
+ +
+
+MSG_ERR_NO_LOGIN = 미접속상태[source]
+
+ +
+
+MSG_ERR_LOGIN = 로그인시 접속 실패 (아이피 오류 또는 접속정보 오류)[source]
+
+ +
+
+MSG_ERR_CONNECT = 서버 접속 실패[source]
+
+ +
+
+MSG_ERR_VERSION = 버전처리가 실패하였습니다.[source]
+
+ +
+
+MSG_ERR_TRCODE = TrCode 가 존재하지 않습니다.[source]
+
+ +
+
+MSG_ERR_NO_REGOPENAPI = 해외OpenAPI 미신청[source]
+
+ +
+
+MSG_ERR_SISE_OVERFLOW = 조회과부화[source]
+
+ +
+
+MSG_ERR_ORDER_OVERFLOW = 주문과부화[source]
+
+ +
+
+MSG_ERR_RQ_WRONG_INPUT = 조회입력값(명칭/누락) 오류[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_INPUT = 주문입력갑 오류[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_ACCPWD = 계좌비밀번호를 입력하십시오.[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_ACCNO = 타인 계좌를 사용할 수 없습니다.[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_QTY200 = 경고-주문수량 200개 초과[source]
+
+ +
+
+MSG_ERR_ORD_WRONG_QTY400 = 제한-주문수량 400개 초과[source]
+
+ +
+
+ERROR_MESSAGE_BY_CODE[source]
+
+ +
+
+classmethod get_error_message_by_code(cls, code, default=None)[source]
+
+ +
+
+classmethod check_code_or_raise(cls, code)[source]
+
+ +
+
+classmethod wrap_to_check_code_or_raise(cls, func)[source]
+
+ +
+
+classmethod try_or_raise(cls, arg, message=None)[source]
+
+ +
+
+property code(self)[source]
+
+ +
+ +
+
+exception koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWBooleanReturnCodeError(code, message=None)[source]
+

Bases: KiwoomOpenApiWError

+

Common base class for all non-exit exceptions.

+
+
+OP_ERR_SUCCESS = 1[source]
+
+ +
+
+OP_ERR_FAILURE = 0[source]
+
+ +
+
+classmethod check_code_or_raise(cls, code, message=None)[source]
+
+ +
+
+classmethod wrap_to_check_code_or_raise(cls, func, message=None)[source]
+
+ +
+
+classmethod try_or_raise(cls, arg, message=None)[source]
+
+ +
+
+property code(self)[source]
+
+ +
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.html new file mode 100644 index 00000000..c70a0141 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.html @@ -0,0 +1,251 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWEventHandler

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler.KiwoomOpenApiWEventHandler(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions.KiwoomOpenApiWEventHandlerFunctions

+
+
+property control(self)[source]
+
+ +
+
+property observer(self)[source]
+
+ +
+
+classmethod names(cls)[source]
+
+ +
+
+slots(self)[source]
+
+ +
+
+connect(self)[source]
+
+ +
+
+disconnect(self)[source]
+
+ +
+
+on_enter(self)[source]
+
+ +
+
+on_exit(self, exc_type=None, exc_value=None, traceback=None)[source]
+
+ +
+
+add_callback(self, callback, *args, **kwargs)[source]
+
+ +
+
+enter(self)[source]
+
+ +
+
+exit(self, exc_type=None, exc_value=None, traceback=None)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+close(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.html new file mode 100644 index 00000000..86db530c --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.html @@ -0,0 +1,210 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWEventHandlerFunctions

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions.KiwoomOpenApiWEventHandlerFunctions[source]
+
+
+abstract OnEventConnect(self, errcode)[source]
+
+ +
+
+abstract OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+abstract OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext)[source]
+
+ +
+
+abstract OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+abstract OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.html new file mode 100644 index 00000000..2f35c195 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.html @@ -0,0 +1,211 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWLoggingEventHandler

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler.KiwoomOpenApiWLoggingEventHandler(control)[source]
+

Bases: koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler.KiwoomOpenApiWEventHandler, koapy.utils.logging.Logging.Logging

+
+
+OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext)[source]
+
+ +
+
+OnReceiveRealData(self, code, realtype, realdata)[source]
+
+ +
+
+OnReceiveMsg(self, scrnno, rqname, trcode, msg)[source]
+
+ +
+
+OnReceiveChejanData(self, gubun, itemcnt, fidlist)[source]
+
+ +
+
+OnEventConnect(self, errcode)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.html new file mode 100644 index 00000000..fb99c1cb --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.html @@ -0,0 +1,211 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWQAxWidget

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget.KiwoomOpenApiWQAxWidget(*args, **kwargs)[source]
+

Bases: koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging, koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin.KiwoomOpenApiWQAxWidgetMixin

+
+
+CLSID = {D1ACAB7D-A3AF-49E4-9004-C9E98344E17A}[source]
+
+ +
+
+METHOD_NAMES[source]
+
+ +
+
+EVENT_NAMES[source]
+
+ +
+
+changeEvent(self, event)[source]
+
+ +
+
+closeEvent(self, event)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.html new file mode 100644 index 00000000..1c9f4bae --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWQAxWidgetMixin

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin.KiwoomOpenApiWQAxWidgetMixin[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.html new file mode 100644 index 00000000..d4422640 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.html @@ -0,0 +1,211 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KiwoomOpenApiWSignalConnector

+
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector.KiwoomOpenApiWSignalConnector(name=None)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+is_valid_slot(self, slot)[source]
+
+ +
+
+connect_to(self, control)[source]
+
+ +
+
+connect(self, slot)[source]
+
+ +
+
+disconnect(self, slot=None)[source]
+
+ +
+
+call(self, *args, **kwargs)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.html new file mode 100644 index 00000000..d4968ff8 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.html @@ -0,0 +1,485 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiWSignature

A Signature object represents the overall signature of a function.

KiwoomOpenApiWDispatchSignature

A Signature object represents the overall signature of a function.

KiwoomOpenApiWEventHandlerSignature

A Signature object represents the overall signature of a function.

+
+
+

Functions

+ ++++ + + + + + + + + + + + +

BuildOleItems(clsid)

LoadDispatchSignatures(oleItems, clsId)

LoadEventHandlerSignatures(oleItems, clsId)

+
+
+

Attributes

+ ++++ + + + + + + + + +

DISPATCH_SIGNATURES_BY_NAME

EVENT_HANDLER_SIGNATURES_BY_NAME

+
+
+koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.BuildOleItems(clsid)[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWSignature(name, parameters=None, return_annotation=Signature.empty, entry=None)[source]
+

Bases: inspect.Signature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 63); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 63); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 67); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 67); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+MODULE_CLSID = {1F8A15ED-A979-488F-9694-1EDA98188FFC}[source]
+
+ +
+
+OLE_ITEMS[source]
+
+ +
+
+DISPATCH_CLSID = {85B07632-4F84-4CEF-991D-C79DE781363D}[source]
+
+ +
+
+EVENT_CLSID = {952B31F8-06FD-4D5A-A021-5FF57F5030AE}[source]
+
+ +
+
+PYTHONTYPE_TO_QTTYPE[source]
+
+ +
+
+COMTYPE_TO_PYTHONTYPE[source]
+
+ +
+
+property name(self)[source]
+
+ +
+
+to_pyside2_function_prototype(self)[source]
+
+ +
+
+to_pyside2_event_signal(self)[source]
+
+ +
+ +
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWDispatchSignature(name, parameters=None, return_annotation=Signature.empty, entry=None)[source]
+

Bases: KiwoomOpenApiWSignature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 129); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 129); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 133); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 133); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+DISPATCH_SIGNATURES_BY_NAME[source]
+
+ +
+
+classmethod from_name(cls, name)[source]
+
+ +
+
+classmethod names(cls)[source]
+
+ +
+ +
+
+koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.LoadDispatchSignatures(oleItems, clsId)[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.DISPATCH_SIGNATURES_BY_NAME[source]
+
+ +
+
+class koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWEventHandlerSignature(name, parameters=None, return_annotation=Signature.empty, entry=None)[source]
+

Bases: KiwoomOpenApiWSignature

+

A Signature object represents the overall signature of a function. +It stores a Parameter object for each parameter accepted by the +function, as well as information specific to the function itself.

+

A Signature object has the following public attributes and methods:

+
    +
  • +
    parametersOrderedDict

    An ordered mapping of parameters’ names to the corresponding +Parameter objects (keyword-only arguments are in the same order +as listed in code.co_varnames).

    +
    +
    +
  • +
  • +
    return_annotationobject

    The annotation for the return type of the function if specified. +If the function has no annotation for its return type, this +attribute is set to Signature.empty.

    +
    +
    +
  • +
  • +
    bind(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 176); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 176); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a mapping from positional and keyword arguments to +parameters.

    +
    +
    +
  • +
  • +
    bind_partial(*args, **kwargs) -> BoundArguments
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 180); backlink

    +

    Inline emphasis start-string without end-string.

    +
    +
    +

    System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst, line 180); backlink

    +

    Inline strong start-string without end-string.

    +
    +

    Creates a partial mapping from positional and keyword arguments +to parameters (simulating ‘functools.partial’ behavior.)

    +
    +
    +
  • +
+
+
+EVENT_HANDLER_SIGNATURES_BY_NAME[source]
+
+ +
+
+classmethod from_name(cls, name)[source]
+
+ +
+
+classmethod names(cls)[source]
+
+ +
+ +
+
+koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.LoadEventHandlerSignatures(oleItems, clsId)[source]
+
+ +
+
+koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.EVENT_HANDLER_SIGNATURES_BY_NAME[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/core/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/core/index.html new file mode 100644 index 00000000..26e0c1a7 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/core/index.html @@ -0,0 +1,178 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w.core — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backend/kiwoom_open_api_w/index.html b/autoapi/koapy/backend/kiwoom_open_api_w/index.html new file mode 100644 index 00000000..843a0085 --- /dev/null +++ b/autoapi/koapy/backend/kiwoom_open_api_w/index.html @@ -0,0 +1,179 @@ + + + + + + + + + koapy.backend.kiwoom_open_api_w — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.html b/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.html new file mode 100644 index 00000000..0912ef76 --- /dev/null +++ b/autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.html @@ -0,0 +1,290 @@ + + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusBroker — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KiwoomOpenApiPlusBroker

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KiwoomOpenApiPlusCommInfo

MetaKiwoomOpenApiPlusBroker

KiwoomOpenApiPlusBroker

+
+
+class koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusCommInfo(*args, **kwargs)[source]
+

Bases: backtrader.comminfo.CommInfoBase

+
+
+params = [['stocklike', True], None, ['percabs', False], ['commission', 0.015], ['tax', 0.25], ['mult', 1.0]][source]
+
+ +
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusBroker.MetaKiwoomOpenApiPlusBroker(cls, name, bases, dct)[source]
+

Bases: backtrader.BrokerBase.__class__

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusBroker(*args, **kwargs)[source]
+

Bases: with_metaclass(MetaKiwoomOpenApiPlusBroker, BrokerBase)

+
+
+params = [['use_positions', True], None][source]
+
+ +
+
+start(self)[source]
+
+ +
+
+data_started(self, data)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+getcash(self)[source]
+
+ +
+
+getvalue(self, datas=None)[source]
+
+ +
+
+getposition(self, data, clone=True)[source]
+
+ +
+
+orderstatus(self, order)[source]
+
+ +
+
+buy(self, owner, data, size, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)[source]
+
+ +
+
+sell(self, owner, data, size, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)[source]
+
+ +
+
+cancel(self, order)[source]
+
+ +
+
+notify(self, order)[source]
+
+ +
+
+get_notification(self)[source]
+
+ +
+
+next(self)[source]
+
+ +
+
+submit(self, order)[source]
+
+ +
+
+add_order_history(self, orders, notify=False)[source]
+
+ +
+
+set_fund_history(self, fund)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.html b/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.html new file mode 100644 index 00000000..e51f3b2d --- /dev/null +++ b/autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.html @@ -0,0 +1,246 @@ + + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KiwoomOpenApiPlusData

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

MetaKiwoomOpenApiPlusData

KiwoomOpenApiPlusData

+
+
+class koapy.backtrader.KiwoomOpenApiPlusData.MetaKiwoomOpenApiPlusData(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(DataBase)

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusData.KiwoomOpenApiPlusData(*args, **kwargs)[source]
+

Bases: backtrader.feed.DataBase, koapy.utils.logging.Logging.Logging

+
+
+params = [['qcheck', 0.5], ['historical', False], ['backfill_start', True], ['backfill', True],...[source]
+
+ +
+
+isnaive(self, dt)[source]
+
+ +
+
+asutc(self, dt, tz=None, naive=True)[source]
+
+ +
+
+date2num(self, dt, tz=None)[source]
+
+ +
+
+num2date(self, dt=None, tz=None, naive=False)[source]
+
+ +
+
+fromtimestamp(self, timestamp, tz=None)[source]
+
+ +
+
+islive(self)[source]
+
+ +
+
+setenvironment(self, env)[source]
+
+ +
+
+start(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+haslivedata(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.html b/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.html new file mode 100644 index 00000000..d0bb60c6 --- /dev/null +++ b/autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.html @@ -0,0 +1,344 @@ + + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusEventStreamer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KiwoomOpenApiPlusEventStreamer

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + +

KiwoomOpenApiPlusPriceEventChannel

KiwoomOpenApiPlusOrderEventChannel

MetaKiwoomOpenApiPlusEventStreamer

Metaclass for defining Abstract Base Classes (ABCs).

KiwoomOpenApiPlusEventStreamer

Observer abstract base class

+
+
+class koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusPriceEventChannel(stub)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+close(self)[source]
+
+ +
+
+initialize(self)[source]
+
+ +
+
+register_code(self, code)[source]
+
+ +
+
+is_for_code(self, response, code)[source]
+
+ +
+
+filter_for_code(self, code)[source]
+
+ +
+
+is_valid_price_event(self, response)[source]
+
+ +
+
+filter_price_event(self)[source]
+
+ +
+
+time_to_timestamp(self, fid20)[source]
+
+ +
+
+event_to_dict(self, response)[source]
+
+ +
+
+convert_to_dict(self)[source]
+
+ +
+
+get_observable_for_code(self, code)[source]
+
+ +
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusOrderEventChannel(stub)[source]
+
+
+close(self)[source]
+
+ +
+
+is_chejan_response(self, response)[source]
+
+ +
+
+filter_chejan_response(self)[source]
+
+ +
+
+event_to_dict(self, response)[source]
+
+ +
+
+convert_to_dict(self)[source]
+
+ +
+
+get_observable(self)[source]
+
+ +
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusEventStreamer.MetaKiwoomOpenApiPlusEventStreamer(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(Observer)

+

Metaclass for defining Abstract Base Classes (ABCs).

+

Use this metaclass to create an ABC. An ABC can be subclassed +directly, and then acts as a mix-in class. You can also register +unrelated concrete classes (even built-in classes) and unrelated +ABCs as ‘virtual subclasses’ – these and their descendants will +be considered subclasses of the registering ABC by the built-in +issubclass() function, but the registering ABC won’t show up in +their MRO (Method Resolution Order) nor will method +implementations defined by the registering ABC be callable (not +even via super()).

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusEventStreamer(stub, queue)[source]
+

Bases: rx.core.typing.Observer, koapy.utils.logging.Logging.Logging

+

Observer abstract base class

+

An Observer is the entity that receives all emissions of a subscribed +Observable.

+
+
+on_next(self, value)[source]
+

Notifies the observer of a new element in the sequence.

+
+
Parameters
+

value – The received element.

+
+
+
+ +
+
+on_error(self, error)[source]
+

Notifies the observer that an exception has occurred.

+
+
Parameters
+

error – The error that has occurred.

+
+
+
+ +
+
+on_completed(self)[source]
+

Notifies the observer of the end of the sequence.

+
+ +
+
+rates(self, code)[source]
+
+ +
+
+events(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.html b/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.html new file mode 100644 index 00000000..0dadf5cd --- /dev/null +++ b/autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.html @@ -0,0 +1,405 @@ + + + + + + + + + koapy.backtrader.KiwoomOpenApiPlusStore — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KiwoomOpenApiPlusStore

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + + + + +

HistoricalPriceRecord

Built-in immutable sequence.

API

MetaSingleton

MetaKiwoomOpenApiPlusStore

KiwoomOpenApiPlusStore

+
+
+exception koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusJsonError(code, message=None)[source]
+

Bases: koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusNegativeReturnCodeError

+

Common base class for all non-exit exceptions.

+
+
+error_response(self, description=None)[source]
+
+ +
+ +
+
+exception koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusTimeFrameError[source]
+

Bases: KiwoomOpenApiPlusJsonError

+

Common base class for all non-exit exceptions.

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusStore.HistoricalPriceRecord[source]
+

Bases: collections.namedtuple('HistoricalPriceRecord', ['time', 'open', 'high', 'low', 'close', 'volume'])

+

Built-in immutable sequence.

+

If no argument is given, the constructor returns an empty tuple. +If iterable is specified the tuple is initialized from iterable’s items.

+

If the argument is a tuple, the return value is the same object.

+
+
+classmethod from_tuple(cls, tup)[source]
+
+ +
+
+classmethod records_from_dataframe(cls, df)[source]
+
+ +
+
+classmethod dict_records_from_dataframe(cls, df)[source]
+
+ +
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusStore.API(context)[source]
+
+
+get_instruments_original(self, account, instruments)[source]
+
+ +
+
+get_instruments(self, account, instruments)[source]
+
+ +
+
+get_history(self, trcode, inputs, dtbegin=None, dtend=None)[source]
+
+ +
+
+get_positions(self, account)[source]
+
+ +
+
+get_account(self, account)[source]
+
+ +
+
+create_order(self, account, **kwargs)[source]
+
+ +
+
+close_order(self, account, oid, size, dataname)[source]
+
+ +
+
+get_today_quotes_by_code(self, codes=None)[source]
+
+ +
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusStore.MetaSingleton(cls, clsname, bases, dct)[source]
+

Bases: backtrader.metabase.MetaParams

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusStore.MetaKiwoomOpenApiPlusStore(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), MetaSingleton

+
+ +
+
+class koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusStore(context=None)[source]
+

Bases: koapy.utils.logging.Logging.Logging

+
+
+BrokerCls[source]
+
+ +
+
+DataCls[source]
+
+ +
+
+params = [['account', ''], ['account_tmout', 60.0]][source]
+
+ +
+
+classmethod getdata(cls, *args, **kwargs)[source]
+
+ +
+
+classmethod getbroker(cls, *args, **kwargs)[source]
+
+ +
+
+start(self, data=None, broker=None)[source]
+
+ +
+
+initial_today_historical_msg(self, data=None)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+put_notification(self, msg, *args, **kwargs)[source]
+
+ +
+
+get_notifications(self)[source]
+
+ +
+
+timeoffset(self)[source]
+
+ +
+
+get_granularity(self, timeframe, compression, default=None)[source]
+
+ +
+
+get_instrument(self, dataname)[source]
+
+ +
+
+streaming_events(self, tmout=None)[source]
+
+ +
+
+candles(self, dataname, dtbegin, dtend, timeframe, compression)[source]
+
+ +
+
+streaming_prices(self, dataname, tmout=None)[source]
+
+ +
+
+get_cash(self)[source]
+
+ +
+
+get_value(self)[source]
+
+ +
+
+get_positions(self)[source]
+
+ +
+
+broker_threads(self)[source]
+
+ +
+
+order_create(self, order, stopside=None, takeside=None, **kwargs)[source]
+
+ +
+
+order_cancel(self, order)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.html b/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.html new file mode 100644 index 00000000..9be18b06 --- /dev/null +++ b/autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.html @@ -0,0 +1,207 @@ + + + + + + + + + koapy.backtrader.KrxHistoricalDailyPriceData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KrxHistoricalDailyPriceData

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KrxHistoricalDailyPriceData

+
+
+class koapy.backtrader.KrxHistoricalDailyPriceData.KrxHistoricalDailyPriceData[source]
+

Bases: backtrader.feed.DataBase

+
+
+params = [['loader', None], ['symbol', None], ['name', None], ['fromdate', None], ['todate', None],...[source]
+
+ +
+
+lines = ['amount', 'marketcap', 'shares'][source]
+
+ +
+
+start(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+
+classmethod adddata_fromfile(cls, cerebro, filename, symbols=None, fromdate=None, todate=None, progress_bar=True)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.html b/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.html new file mode 100644 index 00000000..d13a3199 --- /dev/null +++ b/autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.html @@ -0,0 +1,202 @@ + + + + + + + + + koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KrxHistoricalDailyPriceDataFromSQLite

+
+
+class koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite.KrxHistoricalDailyPriceDataFromSQLite[source]
+

Bases: koapy.backtrader.SQLiteData.SQLiteData

+
+
+params = [['engine', None], ['symbol', None], ['name', None], ['fromdate', None], ['todate', None],...[source]
+
+ +
+
+lines = ['amount', 'marketcap', 'shares'][source]
+
+ +
+
+classmethod dump_from_store(cls, source_filename, dest_filename, symbols=None, fromdate=None, todate=None, progress_bar=True)[source]
+
+ +
+
+classmethod adddata_fromfile(cls, cerebro, filename, symbols=None, fromdate=None, todate=None, progress_bar=True)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/KrxTradingCalendar/index.html b/autoapi/koapy/backtrader/KrxTradingCalendar/index.html new file mode 100644 index 00000000..9318c733 --- /dev/null +++ b/autoapi/koapy/backtrader/KrxTradingCalendar/index.html @@ -0,0 +1,209 @@ + + + + + + + + + koapy.backtrader.KrxTradingCalendar — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.KrxTradingCalendar

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

ExchangeCalendarsTradingCalendar

KrxTradingCalendar

+
+
+class koapy.backtrader.KrxTradingCalendar.ExchangeCalendarsTradingCalendar[source]
+

Bases: backtrader.tradingcal.TradingCalendarBase

+
+
+params = [['calendar', None], ['cachesize', 365]][source]
+
+ +
+
+schedule(self, day, tz=None)[source]
+

day: expecting naive datetime.datetime day in utc timezone +tz: treat/localize internal naive datetimes to this timezone +returns: (opening, closing) naive datetime.datetime pair in utc timezone

+
+ +
+ +
+
+class koapy.backtrader.KrxTradingCalendar.KrxTradingCalendar[source]
+

Bases: ExchangeCalendarsTradingCalendar

+
+
+params = [['calendar', 'XKRX'], ['cachesize', 365]][source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/SQLAlchemyData/index.html b/autoapi/koapy/backtrader/SQLAlchemyData/index.html new file mode 100644 index 00000000..d02b4f97 --- /dev/null +++ b/autoapi/koapy/backtrader/SQLAlchemyData/index.html @@ -0,0 +1,197 @@ + + + + + + + + + koapy.backtrader.SQLAlchemyData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.SQLAlchemyData

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLAlchemyData

+
+
+class koapy.backtrader.SQLAlchemyData.SQLAlchemyData[source]
+

Bases: backtrader.feed.DataBase

+
+
+params = [['url', None], ['engine', None], ['connection', None], ['tablename', None], ['timestampcolumn',...[source]
+
+ +
+
+start(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.html b/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.html new file mode 100644 index 00000000..c035b923 --- /dev/null +++ b/autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.backtrader.SQLAlchemySQLiteData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.SQLAlchemySQLiteData

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLAlchemySQLiteData

+
+
+class koapy.backtrader.SQLAlchemySQLiteData.SQLAlchemySQLiteData[source]
+

Bases: koapy.backtrader.SQLAlchemyData.SQLAlchemyData

+
+
+params = [['filename', None]][source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/SQLiteData/index.html b/autoapi/koapy/backtrader/SQLiteData/index.html new file mode 100644 index 00000000..ffcd38c8 --- /dev/null +++ b/autoapi/koapy/backtrader/SQLiteData/index.html @@ -0,0 +1,197 @@ + + + + + + + + + koapy.backtrader.SQLiteData — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.backtrader.SQLiteData

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLiteData

+
+
+class koapy.backtrader.SQLiteData.SQLiteData[source]
+

Bases: backtrader.feed.DataBase

+
+
+params = [['filename', None], ['connection', None], ['engine', None], ['tablename', None],...[source]
+
+ +
+
+start(self)[source]
+
+ +
+
+stop(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/backtrader/index.html b/autoapi/koapy/backtrader/index.html new file mode 100644 index 00000000..675413ad --- /dev/null +++ b/autoapi/koapy/backtrader/index.html @@ -0,0 +1,174 @@ + + + + + + + + + koapy.backtrader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/__main__/index.html b/autoapi/koapy/cli/__main__/index.html new file mode 100644 index 00000000..394fc80d --- /dev/null +++ b/autoapi/koapy/cli/__main__/index.html @@ -0,0 +1,146 @@ + + + + + + + + + koapy.cli.__main__ — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.__main__

+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/disable/auto_login/index.html b/autoapi/koapy/cli/commands/disable/auto_login/index.html new file mode 100644 index 00000000..3b6cc9cf --- /dev/null +++ b/autoapi/koapy/cli/commands/disable/auto_login/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.cli.commands.disable.auto_login — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.disable.auto_login

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

disable_auto_login_after_login(port)

disable_auto_login_without_login()

auto_login(port)

+
+
+koapy.cli.commands.disable.auto_login.disable_auto_login_after_login(port)[source]
+
+ +
+
+koapy.cli.commands.disable.auto_login.disable_auto_login_without_login()[source]
+
+ +
+
+koapy.cli.commands.disable.auto_login.auto_login(port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/disable/index.html b/autoapi/koapy/cli/commands/disable/index.html new file mode 100644 index 00000000..9f1ad2fe --- /dev/null +++ b/autoapi/koapy/cli/commands/disable/index.html @@ -0,0 +1,199 @@ + + + + + + + + + koapy.cli.commands.disable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.disable

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + +

auto_login

disable()

+
+
+koapy.cli.commands.disable.auto_login(port)
+
+ +
+
+koapy.cli.commands.disable.disable()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/enable/auto_login/index.html b/autoapi/koapy/cli/commands/enable/auto_login/index.html new file mode 100644 index 00000000..40401839 --- /dev/null +++ b/autoapi/koapy/cli/commands/enable/auto_login/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.cli.commands.enable.auto_login — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.enable.auto_login

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

auto_login(port)

+
+
+koapy.cli.commands.enable.auto_login.auto_login(port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/enable/index.html b/autoapi/koapy/cli/commands/enable/index.html new file mode 100644 index 00000000..cf1918f1 --- /dev/null +++ b/autoapi/koapy/cli/commands/enable/index.html @@ -0,0 +1,199 @@ + + + + + + + + + koapy.cli.commands.enable — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.enable

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + +

auto_login

enable()

+
+
+koapy.cli.commands.enable.auto_login(port)
+
+ +
+
+koapy.cli.commands.enable.enable()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/generate/grpc/index.html b/autoapi/koapy/cli/commands/generate/grpc/index.html new file mode 100644 index 00000000..d76b3aa0 --- /dev/null +++ b/autoapi/koapy/cli/commands/generate/grpc/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.cli.commands.generate.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.generate.grpc

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + +

ssl_credentials

grpc()

+
+
+koapy.cli.commands.generate.grpc.ssl_credentials()
+
+ +
+
+koapy.cli.commands.generate.grpc.grpc()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.html b/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.html new file mode 100644 index 00000000..ba885686 --- /dev/null +++ b/autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.html @@ -0,0 +1,203 @@ + + + + + + + + + koapy.cli.commands.generate.grpc.ssl_credentials — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.generate.grpc.ssl_credentials

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

generate_self_signed_key_cert(organization_name, common_name, key_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None)

generate_key_cert_signed_by_authority(organization_name, common_name, alternative_dns_names=None, key_filename=None, csr_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None, authority_key_filename=None, authority_cert_filename=None, authority_key_password=None)

ssl_credentials()

+
+
+koapy.cli.commands.generate.grpc.ssl_credentials.generate_self_signed_key_cert(organization_name, common_name, key_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None)[source]
+
+ +
+
+koapy.cli.commands.generate.grpc.ssl_credentials.generate_key_cert_signed_by_authority(organization_name, common_name, alternative_dns_names=None, key_filename=None, csr_filename=None, cert_filename=None, key_password=None, country_name=None, state_or_province_name=None, locality_name=None, valid_days=None, authority_key_filename=None, authority_cert_filename=None, authority_key_password=None)[source]
+
+ +
+
+koapy.cli.commands.generate.grpc.ssl_credentials.ssl_credentials()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/generate/index.html b/autoapi/koapy/cli/commands/generate/index.html new file mode 100644 index 00000000..fa5ca877 --- /dev/null +++ b/autoapi/koapy/cli/commands/generate/index.html @@ -0,0 +1,214 @@ + + + + + + + + + koapy.cli.commands.generate — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.generate

+
+

Subpackages

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

grpc

openapi

generate()

+
+
+koapy.cli.commands.generate.grpc()
+
+ +
+
+koapy.cli.commands.generate.openapi()
+
+ +
+
+koapy.cli.commands.generate.generate()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/generate/openapi/index.html b/autoapi/koapy/cli/commands/generate/openapi/index.html new file mode 100644 index 00000000..9641fabd --- /dev/null +++ b/autoapi/koapy/cli/commands/generate/openapi/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.cli.commands.generate.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.generate.openapi

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + +

python_stubs

openapi()

+
+
+koapy.cli.commands.generate.openapi.python_stubs(dispatch_class_name, dispatch_file_path, event_class_name, event_file_path, encoding, force_overwrite)
+
+ +
+
+koapy.cli.commands.generate.openapi.openapi()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.html b/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.html new file mode 100644 index 00000000..900b313c --- /dev/null +++ b/autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.html @@ -0,0 +1,230 @@ + + + + + + + + + koapy.cli.commands.generate.openapi.python_stubs — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.generate.openapi.python_stubs

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

python_stubs(dispatch_class_name, dispatch_file_path, event_class_name, event_file_path, encoding, force_overwrite)

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + +

default_dispatch_class_name

default_dispatch_file_path

default_event_class_name

default_event_file_path

+
+
+koapy.cli.commands.generate.openapi.python_stubs.default_dispatch_class_name = KiwoomOpenApiPlusDispatchFunctionsGenerated[source]
+
+ +
+
+koapy.cli.commands.generate.openapi.python_stubs.default_dispatch_file_path[source]
+
+ +
+
+koapy.cli.commands.generate.openapi.python_stubs.default_event_class_name = KiwoomOpenApiPlusEventFunctionsGenerated[source]
+
+ +
+
+koapy.cli.commands.generate.openapi.python_stubs.default_event_file_path[source]
+
+ +
+
+koapy.cli.commands.generate.openapi.python_stubs.python_stubs(dispatch_class_name, dispatch_file_path, event_class_name, event_file_path, encoding, force_overwrite)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/account_data/deposit/index.html b/autoapi/koapy/cli/commands/get/account_data/deposit/index.html new file mode 100644 index 00000000..1f084992 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/account_data/deposit/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.cli.commands.get.account_data.deposit — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.account_data.deposit

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

deposit(account, port)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.get.account_data.deposit.logger[source]
+
+ +
+
+koapy.cli.commands.get.account_data.deposit.deposit(account, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/account_data/evaluation/index.html b/autoapi/koapy/cli/commands/get/account_data/evaluation/index.html new file mode 100644 index 00000000..618a8668 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/account_data/evaluation/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.cli.commands.get.account_data.evaluation — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.account_data.evaluation

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.get.account_data.evaluation.logger[source]
+
+ +
+
+koapy.cli.commands.get.account_data.evaluation.evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/account_data/index.html b/autoapi/koapy/cli/commands/get/account_data/index.html new file mode 100644 index 00000000..8ab4de95 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/account_data/index.html @@ -0,0 +1,174 @@ + + + + + + + + + koapy.cli.commands.get.account_data — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/account_data/orders/index.html b/autoapi/koapy/cli/commands/get/account_data/orders/index.html new file mode 100644 index 00000000..f9dc21fd --- /dev/null +++ b/autoapi/koapy/cli/commands/get/account_data/orders/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.cli.commands.get.account_data.orders — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.account_data.orders

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.get.account_data.orders.logger[source]
+
+ +
+
+koapy.cli.commands.get.account_data.orders.orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/account_data/userinfo/index.html b/autoapi/koapy/cli/commands/get/account_data/userinfo/index.html new file mode 100644 index 00000000..1157c5cd --- /dev/null +++ b/autoapi/koapy/cli/commands/get/account_data/userinfo/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.account_data.userinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.account_data.userinfo

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

userinfo(port)

+
+
+koapy.cli.commands.get.account_data.userinfo.userinfo(port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/chart_data/daily/index.html b/autoapi/koapy/cli/commands/get/chart_data/daily/index.html new file mode 100644 index 00000000..c5a33890 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/chart_data/daily/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.cli.commands.get.chart_data.daily — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.chart_data.daily

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

daily(code, output, format, start_date, end_date, port)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.get.chart_data.daily.logger[source]
+
+ +
+
+koapy.cli.commands.get.chart_data.daily.daily(code, output, format, start_date, end_date, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/chart_data/index.html b/autoapi/koapy/cli/commands/get/chart_data/index.html new file mode 100644 index 00000000..48f252eb --- /dev/null +++ b/autoapi/koapy/cli/commands/get/chart_data/index.html @@ -0,0 +1,172 @@ + + + + + + + + + koapy.cli.commands.get.chart_data — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/chart_data/minute/index.html b/autoapi/koapy/cli/commands/get/chart_data/minute/index.html new file mode 100644 index 00000000..4379a78f --- /dev/null +++ b/autoapi/koapy/cli/commands/get/chart_data/minute/index.html @@ -0,0 +1,214 @@ + + + + + + + + + koapy.cli.commands.get.chart_data.minute — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.chart_data.minute

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

minute(code, interval, output, format, start_date, end_date, port)

+
+
+

Attributes

+ ++++ + + + + + + + + +

logger

minute_intervals

+
+
+koapy.cli.commands.get.chart_data.minute.logger[source]
+
+ +
+
+koapy.cli.commands.get.chart_data.minute.minute_intervals = ['1', '3', '5', '10', '15', '30', '45', '60'][source]
+
+ +
+
+koapy.cli.commands.get.chart_data.minute.minute(code, interval, output, format, start_date, end_date, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/index.html b/autoapi/koapy/cli/commands/get/index.html new file mode 100644 index 00000000..611ceb9f --- /dev/null +++ b/autoapi/koapy/cli/commands/get/index.html @@ -0,0 +1,365 @@ + + + + + + + + + koapy.cli.commands.get — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get

+
+

Subpackages

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

deposit(account, port)

evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port)

orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port)

userinfo(port)

daily(code, output, format, start_date, end_date, port)

minute(code, interval, output, format, start_date, end_date, port)

errmsg(err_code)

modulepath()

realinfo(realtypes)

trinfo(trcodes)

codelist(markets, port)



stockcode(names, markets, port)



stockinfo(code, output, format, port)

stockname(codes, port)

get()

+
+
+koapy.cli.commands.get.deposit(account, port)[source]
+
+ +
+
+koapy.cli.commands.get.evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port)[source]
+
+ +
+
+koapy.cli.commands.get.orders(account, date, reverse, executed_only, not_executed_only, stock_only, bond_only, sell_only, buy_only, code, starting_order_no, port)[source]
+
+ +
+
+koapy.cli.commands.get.userinfo(port)[source]
+
+ +
+
+koapy.cli.commands.get.daily(code, output, format, start_date, end_date, port)[source]
+
+ +
+
+koapy.cli.commands.get.minute(code, interval, output, format, start_date, end_date, port)[source]
+
+ +
+
+koapy.cli.commands.get.errmsg(err_code)[source]
+
+ +
+
+koapy.cli.commands.get.modulepath()[source]
+
+ +
+
+koapy.cli.commands.get.realinfo(realtypes)[source]
+
+ +
+
+koapy.cli.commands.get.trinfo(trcodes)[source]
+
+ +
+
+koapy.cli.commands.get.codelist(markets, port)[source]
+

 +Possible market codes are:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/commands/get/index.rst, line 80)

+

Unexpected indentation.

+
+
+

0 : 장내 +10 : 코스닥 +3 : ELW +8 : ETF +50 : KONEX +4 : 뮤추얼펀드 +5 : 신주인수권 +6 : 리츠 +9 : 하이얼펀드 +30 : K-OTC

+
+
+ +
+
+koapy.cli.commands.get.stockcode(names, markets, port)[source]
+

 +Possible market codes are:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/commands/get/index.rst, line 96)

+

Unexpected indentation.

+
+
+

0 : 장내 +10 : 코스닥 +3 : ELW +8 : ETF +50 : KONEX +4 : 뮤추얼펀드 +5 : 신주인수권 +6 : 리츠 +9 : 하이얼펀드 +30 : K-OTC

+
+
+ +
+
+koapy.cli.commands.get.stockinfo(code, output, format, port)[source]
+
+ +
+
+koapy.cli.commands.get.stockname(codes, port)[source]
+
+ +
+
+koapy.cli.commands.get.get()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.html b/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.html new file mode 100644 index 00000000..b4adea07 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.openapi_meta.errmsg — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.openapi_meta.errmsg

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

errmsg(err_code)

+
+
+koapy.cli.commands.get.openapi_meta.errmsg.errmsg(err_code)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/openapi_meta/index.html b/autoapi/koapy/cli/commands/get/openapi_meta/index.html new file mode 100644 index 00000000..da0d8f06 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/openapi_meta/index.html @@ -0,0 +1,174 @@ + + + + + + + + + koapy.cli.commands.get.openapi_meta — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.html b/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.html new file mode 100644 index 00000000..220c09f3 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.openapi_meta.modulepath — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.openapi_meta.modulepath

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

modulepath()

+
+
+koapy.cli.commands.get.openapi_meta.modulepath.modulepath()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.html b/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.html new file mode 100644 index 00000000..abe0b666 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.openapi_meta.realinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.openapi_meta.realinfo

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

realinfo(realtypes)

+
+
+koapy.cli.commands.get.openapi_meta.realinfo.realinfo(realtypes)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.html b/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.html new file mode 100644 index 00000000..17587806 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.openapi_meta.trinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.openapi_meta.trinfo

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

trinfo(trcodes)

+
+
+koapy.cli.commands.get.openapi_meta.trinfo.trinfo(trcodes)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.html b/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.html new file mode 100644 index 00000000..614ebc40 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.html @@ -0,0 +1,232 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta.codelist — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.stock_meta.codelist

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + +

codelist(markets, port)



main()

+
+
+

Attributes

+ ++++ + + + + + +

market_codes

+
+
+koapy.cli.commands.get.stock_meta.codelist.market_codes = ['0', '10', '3', '8', '50', '4', '5', '6', '9', '30', 'all'][source]
+
+ +
+
+koapy.cli.commands.get.stock_meta.codelist.codelist(markets, port)[source]
+

 +Possible market codes are:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/commands/get/stock_meta/codelist/index.rst, line 38)

+

Unexpected indentation.

+
+
+

0 : 장내 +10 : 코스닥 +3 : ELW +8 : ETF +50 : KONEX +4 : 뮤추얼펀드 +5 : 신주인수권 +6 : 리츠 +9 : 하이얼펀드 +30 : K-OTC

+
+
+ +
+
+koapy.cli.commands.get.stock_meta.codelist.main()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.html b/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.html new file mode 100644 index 00000000..ff878b71 --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.html @@ -0,0 +1,322 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta.codelist_interactive — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.stock_meta.codelist_interactive

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + + + + +

MarketEntry

StockEntry

StatusBarHandler

Handler instances dispatch logging events to specific destinations.

Screen

+
+
+

Functions

+ ++++ + + + + + + + + + + + + + + +

screen_len(str)

wrapper(stdscr)

codelist_interactive()

main()

+
+
+

Attributes

+ ++++ + + + + + +

markets

+
+
+class koapy.cli.commands.get.stock_meta.codelist_interactive.MarketEntry(code, name)[source]
+
+
+to_string(self)[source]
+
+ +
+ +
+
+class koapy.cli.commands.get.stock_meta.codelist_interactive.StockEntry(code, name)[source]
+
+
+to_string(self)[source]
+
+ +
+ +
+
+koapy.cli.commands.get.stock_meta.codelist_interactive.markets[source]
+
+ +
+
+class koapy.cli.commands.get.stock_meta.codelist_interactive.StatusBarHandler(screen, level=logging.NOTSET)[source]
+

Bases: logging.Handler

+

Handler instances dispatch logging events to specific destinations.

+

The base handler class. Acts as a placeholder which defines the Handler +interface. Handlers can optionally use Formatter instances to format +records as desired. By default, no formatter is specified; in this case, +the ‘raw’ message as determined by record.message is logged.

+
+
+emit(self, record)[source]
+

Do whatever it takes to actually log the specified logging record.

+

This version is intended to be implemented by subclasses and so +raises a NotImplementedError.

+
+ +
+ +
+
+koapy.cli.commands.get.stock_meta.codelist_interactive.screen_len(str)[source]
+
+ +
+
+class koapy.cli.commands.get.stock_meta.codelist_interactive.Screen(screen)[source]
+
+
+refresh_header_bar(self)[source]
+
+ +
+
+set_header_bar(self, text)[source]
+
+ +
+ +
+ +
+ +
+ +
+
+show_entries(self, entries)[source]
+
+ +
+ +
+
+koapy.cli.commands.get.stock_meta.codelist_interactive.wrapper(stdscr)[source]
+
+ +
+
+koapy.cli.commands.get.stock_meta.codelist_interactive.codelist_interactive()[source]
+
+ +
+
+koapy.cli.commands.get.stock_meta.codelist_interactive.main()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/index.html b/autoapi/koapy/cli/commands/get/stock_meta/index.html new file mode 100644 index 00000000..cb62934a --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/index.html @@ -0,0 +1,175 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.html b/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.html new file mode 100644 index 00000000..5dd0c2ce --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.html @@ -0,0 +1,224 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta.stockcode — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.stock_meta.stockcode

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

stockcode(names, markets, port)



+
+
+

Attributes

+ ++++ + + + + + +

market_codes

+
+
+koapy.cli.commands.get.stock_meta.stockcode.market_codes = ['0', '10', '3', '8', '50', '4', '5', '6', '9', '30', 'all'][source]
+
+ +
+
+koapy.cli.commands.get.stock_meta.stockcode.stockcode(names, markets, port)[source]
+

 +Possible market codes are:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.rst, line 37)

+

Unexpected indentation.

+
+
+

0 : 장내 +10 : 코스닥 +3 : ELW +8 : ETF +50 : KONEX +4 : 뮤추얼펀드 +5 : 신주인수권 +6 : 리츠 +9 : 하이얼펀드 +30 : K-OTC

+
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.html b/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.html new file mode 100644 index 00000000..17b9dbbb --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta.stockinfo — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.stock_meta.stockinfo

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

stockinfo(code, output, format, port)

+
+
+koapy.cli.commands.get.stock_meta.stockinfo.stockinfo(code, output, format, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.html b/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.html new file mode 100644 index 00000000..a1b2d80a --- /dev/null +++ b/autoapi/koapy/cli/commands/get/stock_meta/stockname/index.html @@ -0,0 +1,187 @@ + + + + + + + + + koapy.cli.commands.get.stock_meta.stockname — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.get.stock_meta.stockname

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

stockname(codes, port)

+
+
+koapy.cli.commands.get.stock_meta.stockname.stockname(codes, port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/index.html b/autoapi/koapy/cli/commands/index.html new file mode 100644 index 00000000..9ffc27e0 --- /dev/null +++ b/autoapi/koapy/cli/commands/index.html @@ -0,0 +1,231 @@ + + + + + + + + + koapy.cli.commands — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands

+
+

Subpackages

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/install/index.html b/autoapi/koapy/cli/commands/install/index.html new file mode 100644 index 00000000..c7258cc5 --- /dev/null +++ b/autoapi/koapy/cli/commands/install/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.cli.commands.install — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.install

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

openapi

pywin32

install()

+
+
+koapy.cli.commands.install.openapi(target, cleanup)
+
+ +
+
+koapy.cli.commands.install.pywin32(version)
+
+ +
+
+koapy.cli.commands.install.install()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/install/openapi/index.html b/autoapi/koapy/cli/commands/install/openapi/index.html new file mode 100644 index 00000000..74f74ce1 --- /dev/null +++ b/autoapi/koapy/cli/commands/install/openapi/index.html @@ -0,0 +1,204 @@ + + + + + + + + + koapy.cli.commands.install.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.install.openapi

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

openapi(target, cleanup)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.install.openapi.logger[source]
+
+ +
+
+koapy.cli.commands.install.openapi.openapi(target, cleanup)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/install/pywin32/index.html b/autoapi/koapy/cli/commands/install/pywin32/index.html new file mode 100644 index 00000000..ddd01a0a --- /dev/null +++ b/autoapi/koapy/cli/commands/install/pywin32/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.cli.commands.install.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.install.pywin32

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

pywin32(version)

+
+
+koapy.cli.commands.install.pywin32.pywin32(version)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/serve/index.html b/autoapi/koapy/cli/commands/serve/index.html new file mode 100644 index 00000000..faa3077c --- /dev/null +++ b/autoapi/koapy/cli/commands/serve/index.html @@ -0,0 +1,199 @@ + + + + + + + + + koapy.cli.commands.serve — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.serve

+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

grpc_server_and_client_options()

full_verbose_option(*args, **kwargs)

serve(ctx, verbose, **kwargs)

+
+
+koapy.cli.commands.serve.grpc_server_and_client_options()[source]
+
+ +
+
+koapy.cli.commands.serve.full_verbose_option(*args, **kwargs)[source]
+
+ +
+
+koapy.cli.commands.serve.serve(ctx, verbose, **kwargs)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/show/account_window/index.html b/autoapi/koapy/cli/commands/show/account_window/index.html new file mode 100644 index 00000000..c0108caf --- /dev/null +++ b/autoapi/koapy/cli/commands/show/account_window/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.cli.commands.show.account_window — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.show.account_window

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

account_window(port)

+
+
+koapy.cli.commands.show.account_window.account_window(port)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/show/index.html b/autoapi/koapy/cli/commands/show/index.html new file mode 100644 index 00000000..21e48044 --- /dev/null +++ b/autoapi/koapy/cli/commands/show/index.html @@ -0,0 +1,199 @@ + + + + + + + + + koapy.cli.commands.show — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.show

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + +

account_window

show()

+
+
+koapy.cli.commands.show.account_window(port)
+
+ +
+
+koapy.cli.commands.show.show()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/uninstall/index.html b/autoapi/koapy/cli/commands/uninstall/index.html new file mode 100644 index 00000000..34526ced --- /dev/null +++ b/autoapi/koapy/cli/commands/uninstall/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.cli.commands.uninstall — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.uninstall

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

openapi

pywin32

uninstall()

+
+
+koapy.cli.commands.uninstall.openapi(reboot, cleanup)
+
+ +
+
+koapy.cli.commands.uninstall.pywin32()
+
+ +
+
+koapy.cli.commands.uninstall.uninstall()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/uninstall/openapi/index.html b/autoapi/koapy/cli/commands/uninstall/openapi/index.html new file mode 100644 index 00000000..59e21b64 --- /dev/null +++ b/autoapi/koapy/cli/commands/uninstall/openapi/index.html @@ -0,0 +1,204 @@ + + + + + + + + + koapy.cli.commands.uninstall.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.uninstall.openapi

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

openapi(reboot, cleanup)

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.commands.uninstall.openapi.logger[source]
+
+ +
+
+koapy.cli.commands.uninstall.openapi.openapi(reboot, cleanup)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/uninstall/pywin32/index.html b/autoapi/koapy/cli/commands/uninstall/pywin32/index.html new file mode 100644 index 00000000..face35d9 --- /dev/null +++ b/autoapi/koapy/cli/commands/uninstall/pywin32/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.cli.commands.uninstall.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.uninstall.pywin32

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

pywin32()

+
+
+koapy.cli.commands.uninstall.pywin32.pywin32()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/commands/update/index.html b/autoapi/koapy/cli/commands/update/index.html new file mode 100644 index 00000000..7e8d4952 --- /dev/null +++ b/autoapi/koapy/cli/commands/update/index.html @@ -0,0 +1,231 @@ + + + + + + + + + koapy.cli.commands.update — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.commands.update

+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + +

get_credentials(interactive=False)

verbose_option(*args, **kwargs)

update()

trinfo()

realtype()

openapi(interactive)

proto()

+
+
+koapy.cli.commands.update.get_credentials(interactive=False)[source]
+
+ +
+
+koapy.cli.commands.update.verbose_option(*args, **kwargs)[source]
+
+ +
+
+koapy.cli.commands.update.update()[source]
+
+ +
+
+koapy.cli.commands.update.trinfo()[source]
+
+ +
+
+koapy.cli.commands.update.realtype()[source]
+
+ +
+
+koapy.cli.commands.update.openapi(interactive)[source]
+
+ +
+
+koapy.cli.commands.update.proto()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/extensions/functools/index.html b/autoapi/koapy/cli/extensions/functools/index.html new file mode 100644 index 00000000..b621dd12 --- /dev/null +++ b/autoapi/koapy/cli/extensions/functools/index.html @@ -0,0 +1,183 @@ + + + + + + + + + koapy.cli.extensions.functools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.extensions.functools

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

update_wrapper_with_click_params(wrapper, wrapped, *args, **kwargs)

+
+
+koapy.cli.extensions.functools.update_wrapper_with_click_params(wrapper, wrapped, *args, **kwargs)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/extensions/index.html b/autoapi/koapy/cli/extensions/index.html new file mode 100644 index 00000000..d1c626f7 --- /dev/null +++ b/autoapi/koapy/cli/extensions/index.html @@ -0,0 +1,169 @@ + + + + + + + + + koapy.cli.extensions — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/extensions/parser/index.html b/autoapi/koapy/cli/extensions/parser/index.html new file mode 100644 index 00000000..190b2b17 --- /dev/null +++ b/autoapi/koapy/cli/extensions/parser/index.html @@ -0,0 +1,255 @@ + + + + + + + + + koapy.cli.extensions.parser — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.extensions.parser

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

ArgumentParser

ClickArgumentParser

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + +

Function

FunctionOrCommand

ArgumentDecorator

CommandDecorator

+
+
+koapy.cli.extensions.parser.Function[source]
+
+ +
+
+koapy.cli.extensions.parser.FunctionOrCommand[source]
+
+ +
+
+koapy.cli.extensions.parser.ArgumentDecorator[source]
+
+ +
+
+koapy.cli.extensions.parser.CommandDecorator[source]
+
+ +
+
+class koapy.cli.extensions.parser.ArgumentParser[source]
+
+
+abstract parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → argparse.Namespace[source]
+
+ +
+
+abstract parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → Tuple[argparse.Namespace, List[str]][source]
+
+ +
+ +
+
+class koapy.cli.extensions.parser.ClickArgumentParser(params: Sequence[ArgumentDecorator], command: Optional[CommandDecorator] = None, help_option_names: Optional[Sequence[str]] = None)[source]
+

Bases: ArgumentParser

+
+
+parse_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → argparse.Namespace[source]
+
+ +
+
+parse_known_args(self, args: Optional[Sequence[str]] = None, namespace: Optional[argparse.Namespace] = None) → Tuple[argparse.Namespace, List[str]][source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/extensions/verbose_option/index.html b/autoapi/koapy/cli/extensions/verbose_option/index.html new file mode 100644 index 00000000..81f48e93 --- /dev/null +++ b/autoapi/koapy/cli/extensions/verbose_option/index.html @@ -0,0 +1,285 @@ + + + + + + + + + koapy.cli.extensions.verbose_option — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.extensions.verbose_option

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

VerboseOption

Options are usually optional values on the command line and

+
+
+

Functions

+ ++++ + + + + + + + + + + + +

verbose_flag_option(default=0, flag_value=1, show_default=False, metavar='[0...5]', help='Set verbosity level.')

no_verbose_flag_option(help='Force zero verbosity.')

verbose_option(dest='verbose', default=0, flag_value=1, callback=None, expose_value=False, show_default=False)

+
+
+class koapy.cli.extensions.verbose_option.VerboseOption(*decls, **attrs)[source]
+

Bases: click.Option

+

Options are usually optional values on the command line and +have some extra features that arguments don’t have.

+

All other parameters are passed onwards to the parameter constructor.

+
+
Parameters
+
    +
  • show_default – Show the default value for this option in its +help text. Values are not shown by default, unless +Context.show_default is True. If this value is a +string, it shows that string in parentheses instead of the +actual value. This is particularly useful for dynamic options. +For single option boolean flags, the default remains hidden if +its value is False.

  • +
  • show_envvar – Controls if an environment variable should be +shown on the help page. Normally, environment variables are not +shown.

  • +
  • prompt – If set to True or a non empty string then the +user will be prompted for input. If set to True the prompt +will be the option name capitalized.

  • +
  • confirmation_prompt – Prompt a second time to confirm the +value if it was prompted for. Can be set to a string instead of +True to customize the message.

  • +
  • prompt_required – If set to False, the user will be +prompted for input only when the option was specified as a flag +without a value.

  • +
  • hide_input – If this is True then the input on the prompt +will be hidden from the user. This is useful for password input.

  • +
  • is_flag – forces this option to act as a flag. The default is +auto detection.

  • +
  • flag_value – which value should be used for this flag if it’s +enabled. This is set to a boolean automatically if +the option string contains a slash to mark two options.

  • +
  • multiple – if this is set to True then the argument is accepted +multiple times and recorded. This is similar to nargs +in how it works but supports arbitrary number of +arguments.

  • +
  • count – this flag makes an option increment an integer.

  • +
  • allow_from_autoenv – if this is enabled then the value of this +parameter will be pulled from an environment +variable in case a prefix is defined on the +context.

  • +
  • help – the help string.

  • +
  • hidden – hide this option from help outputs.

  • +
+
+
+
+

Changed in version 8.1.0: Help text indentation is cleaned here instead of only in the +@option decorator.

+
+
+

Changed in version 8.1.0: The show_default parameter overrides +Context.show_default.

+
+
+

Changed in version 8.1.0: The default of a single option boolean flag is not shown if the +default value is False.

+
+
+

Changed in version 8.0.1: type is detected from flag_value if given.

+
+
+
+add_to_parser(self, parser, ctx)[source]
+
+ +
+ +
+
+koapy.cli.extensions.verbose_option.verbose_flag_option(default=0, flag_value=1, show_default=False, metavar='[0...5]', help='Set verbosity level.')[source]
+
+ +
+
+koapy.cli.extensions.verbose_option.no_verbose_flag_option(help='Force zero verbosity.')[source]
+
+ +
+
+koapy.cli.extensions.verbose_option.verbose_option(dest='verbose', default=0, flag_value=1, callback=None, expose_value=False, show_default=False)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/index.html b/autoapi/koapy/cli/index.html new file mode 100644 index 00000000..22a25c1a --- /dev/null +++ b/autoapi/koapy/cli/index.html @@ -0,0 +1,473 @@ + + + + + + + + + koapy.cli — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli

+

Console script for koapy.

+
+

Subpackages

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

disable()

enable()

generate()

get()

install()

serve(ctx, verbose, **kwargs)

show()

uninstall()

update()

get_credentials(interactive=False)

fail_with_usage(message=None, ctx=None)

verbose_option(*args, **kwargs)

get_logger(name=None)

cli()

login(interactive, disable_auto_login, port)

watch(codes, input, fids, realtype, output, format, port)

order(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no, format, port)



main()

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + + + + + + + +

default_encoding

logger

help_option_names

context_settings

order_types

quote_types

+
+
+koapy.cli.disable()[source]
+
+ +
+
+koapy.cli.enable()[source]
+
+ +
+
+koapy.cli.generate()[source]
+
+ +
+
+koapy.cli.get()[source]
+
+ +
+
+koapy.cli.install()[source]
+
+ +
+
+koapy.cli.serve(ctx, verbose, **kwargs)[source]
+
+ +
+
+koapy.cli.show()[source]
+
+ +
+
+koapy.cli.uninstall()[source]
+
+ +
+
+koapy.cli.update()[source]
+
+ +
+
+koapy.cli.get_credentials(interactive=False)[source]
+
+ +
+
+koapy.cli.fail_with_usage(message=None, ctx=None)[source]
+
+ +
+
+koapy.cli.verbose_option(*args, **kwargs)[source]
+
+ +
+
+koapy.cli.default_encoding = utf-8[source]
+
+ +
+
+koapy.cli.get_logger(name=None)[source]
+
+ +
+
+koapy.cli.logger[source]
+
+ +
+
+koapy.cli.help_option_names = ['-h', '--help'][source]
+
+ +
+
+koapy.cli.context_settings[source]
+
+ +
+
+koapy.cli.cli()[source]
+
+ +
+
+koapy.cli.login(interactive, disable_auto_login, port)[source]
+
+ +
+
+koapy.cli.watch(codes, input, fids, realtype, output, format, port)[source]
+
+ +
+
+koapy.cli.order_types = ['1', '2', '3', '4', '5', '6'][source]
+
+ +
+
+koapy.cli.quote_types = ['00', '03', '05', '06', '07', '10', '13', '16', '20', '23', '26', '61', '62', '81'][source]
+
+ +
+
+koapy.cli.order(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no, format, port)[source]
+

 +[주문유형]

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/index.rst, line 148)

+

Unexpected indentation.

+
+
+

1 : 신규매수 +2 : 신규매도 +3 : 매수취소 +4 : 매도취소 +5 : 매수정정 +6 : 매도정정

+
+

 +[거래구분]

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/cli/index.rst, line 157)

+

Unexpected indentation.

+
+
+

모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. +00 : 지정가 +03 : 시장가 +05 : 조건부지정가 +06 : 최유리지정가 +07 : 최우선지정가 +10 : 지정가IOC +13 : 시장가IOC +16 : 최유리IOC +20 : 지정가FOK +23 : 시장가FOK +26 : 최유리FOK +61 : 장전시간외종가 +62 : 시간외단일가매매 +81 : 장후시간외종가

+
+
+ +
+
+koapy.cli.main()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/credentials/index.html b/autoapi/koapy/cli/utils/credentials/index.html new file mode 100644 index 00000000..346b8ad8 --- /dev/null +++ b/autoapi/koapy/cli/utils/credentials/index.html @@ -0,0 +1,191 @@ + + + + + + + + + koapy.cli.utils.credentials — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.credentials

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + +

prompt_credentials()

get_credentials(interactive=False)

+
+
+koapy.cli.utils.credentials.prompt_credentials()[source]
+
+ +
+
+koapy.cli.utils.credentials.get_credentials(interactive=False)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/fail_with_usage/index.html b/autoapi/koapy/cli/utils/fail_with_usage/index.html new file mode 100644 index 00000000..bce520b1 --- /dev/null +++ b/autoapi/koapy/cli/utils/fail_with_usage/index.html @@ -0,0 +1,199 @@ + + + + + + + + + koapy.cli.utils.fail_with_usage — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.fail_with_usage

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

get_help(ctx)

get_help_without_usage(ctx)

fail_with_usage(message=None, ctx=None)

+
+
+koapy.cli.utils.fail_with_usage.get_help(ctx)[source]
+
+ +
+
+koapy.cli.utils.fail_with_usage.get_help_without_usage(ctx)[source]
+
+ +
+
+koapy.cli.utils.fail_with_usage.fail_with_usage(message=None, ctx=None)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/grpc_options/index.html b/autoapi/koapy/cli/utils/grpc_options/index.html new file mode 100644 index 00000000..d865b5bf --- /dev/null +++ b/autoapi/koapy/cli/utils/grpc_options/index.html @@ -0,0 +1,522 @@ + + + + + + + + + koapy.cli.utils.grpc_options — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.grpc_options

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

grpc_server_options()

grpc_client_options()

grpc_server_and_client_options()

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

grpc_config

default_server_bind_address

default_server_host

default_server_port

default_client_host

default_client_port

default_common_host

default_common_port

server_bind_address_option

server_port_option

server_key_file_option

server_cert_file_option

server_root_certs_file_option

server_require_client_auth_option

server_no_require_client_auth_option

server_options

client_host_option

client_port_option

client_enable_ssl_option

client_root_certs_file_option

client_key_file_option

client_cert_file_option

client_options

server_and_client_bind_address_option

server_and_client_host_option

server_and_client_port_option

server_and_client_enable_ssl_option

server_and_client_server_key_file_option

server_and_client_server_cert_file_option

server_and_client_server_root_certs_file_option

server_and_client_require_client_auth_option

server_and_client_no_require_client_auth_option

server_and_client_client_root_certs_file_option

server_and_client_client_key_file_option

server_and_client_client_cert_file_option

server_and_client_options

server_argument_parser

client_argument_parser

server_and_client_argument_parser

+
+
+koapy.cli.utils.grpc_options.grpc_config[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_server_bind_address[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_server_host[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_server_port[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_client_host[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_client_port[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_common_host[source]
+
+ +
+
+koapy.cli.utils.grpc_options.default_common_port[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_bind_address_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_port_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_key_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_cert_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_root_certs_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_require_client_auth_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_no_require_client_auth_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_options[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_host_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_port_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_enable_ssl_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_root_certs_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_key_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_cert_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_options[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_bind_address_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_host_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_port_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_enable_ssl_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_server_key_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_server_cert_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_server_root_certs_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_require_client_auth_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_no_require_client_auth_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_client_root_certs_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_client_key_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_client_cert_file_option[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_options[source]
+
+ +
+
+koapy.cli.utils.grpc_options.grpc_server_options()[source]
+
+ +
+
+koapy.cli.utils.grpc_options.grpc_client_options()[source]
+
+ +
+
+koapy.cli.utils.grpc_options.grpc_server_and_client_options()[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_argument_parser[source]
+
+ +
+
+koapy.cli.utils.grpc_options.client_argument_parser[source]
+
+ +
+
+koapy.cli.utils.grpc_options.server_and_client_argument_parser[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/index.html b/autoapi/koapy/cli/utils/index.html new file mode 100644 index 00000000..28e8ae3c --- /dev/null +++ b/autoapi/koapy/cli/utils/index.html @@ -0,0 +1,172 @@ + + + + + + + + + koapy.cli.utils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/openapi/index.html b/autoapi/koapy/cli/utils/openapi/index.html new file mode 100644 index 00000000..775be81d --- /dev/null +++ b/autoapi/koapy/cli/utils/openapi/index.html @@ -0,0 +1,234 @@ + + + + + + + + + koapy.cli.utils.openapi — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.openapi

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + +

download_openapi_installer(filepath)

prepare_issfile_for_install(filepath, target=None)

prepare_issfile_for_uninstall(filepath, reboot=False)

run_installer_with_issfile(installer, issfile, logfile=None, cwd=None)

+
+
+

Attributes

+ ++++ + + + + + + + + +

logger

iss_file_encoding

+
+
+koapy.cli.utils.openapi.logger[source]
+
+ +
+
+koapy.cli.utils.openapi.iss_file_encoding = euc-kr[source]
+
+ +
+
+koapy.cli.utils.openapi.download_openapi_installer(filepath)[source]
+
+ +
+
+koapy.cli.utils.openapi.prepare_issfile_for_install(filepath, target=None)[source]
+
+ +
+
+koapy.cli.utils.openapi.prepare_issfile_for_uninstall(filepath, reboot=False)[source]
+
+ +
+
+koapy.cli.utils.openapi.run_installer_with_issfile(installer, issfile, logfile=None, cwd=None)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/pywin32/index.html b/autoapi/koapy/cli/utils/pywin32/index.html new file mode 100644 index 00000000..f1788776 --- /dev/null +++ b/autoapi/koapy/cli/utils/pywin32/index.html @@ -0,0 +1,218 @@ + + + + + + + + + koapy.cli.utils.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.pywin32

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

get_pywin32_postinstall_script(filepath)

install_pywin32(version=None)

uninstall_pywin32()

+
+
+

Attributes

+ ++++ + + + + + +

logger

+
+
+koapy.cli.utils.pywin32.logger[source]
+
+ +
+
+koapy.cli.utils.pywin32.get_pywin32_postinstall_script(filepath)[source]
+
+ +
+
+koapy.cli.utils.pywin32.install_pywin32(version=None)[source]
+
+ +
+
+koapy.cli.utils.pywin32.uninstall_pywin32()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/cli/utils/verbose_option/index.html b/autoapi/koapy/cli/utils/verbose_option/index.html new file mode 100644 index 00000000..2c295eb6 --- /dev/null +++ b/autoapi/koapy/cli/utils/verbose_option/index.html @@ -0,0 +1,218 @@ + + + + + + + + + koapy.cli.utils.verbose_option — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.cli.utils.verbose_option

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

verbose_option_callback(ctx, param, value)

verbose_option(*args, **kwargs)

full_verbose_option(*args, **kwargs)

+
+
+

Attributes

+ ++++ + + + + + +

full_verbosity

+
+
+koapy.cli.utils.verbose_option.full_verbosity = 5[source]
+
+ +
+
+koapy.cli.utils.verbose_option.verbose_option_callback(ctx, param, value)[source]
+
+ +
+
+koapy.cli.utils.verbose_option.verbose_option(*args, **kwargs)[source]
+
+ +
+
+koapy.cli.utils.verbose_option.full_verbose_option(*args, **kwargs)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/index.html b/autoapi/koapy/compat/index.html new file mode 100644 index 00000000..e4742414 --- /dev/null +++ b/autoapi/koapy/compat/index.html @@ -0,0 +1,178 @@ + + + + + + + + + koapy.compat — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/QtAxContainer/index.html b/autoapi/koapy/compat/pyside2/QtAxContainer/index.html new file mode 100644 index 00000000..ee101bb2 --- /dev/null +++ b/autoapi/koapy/compat/pyside2/QtAxContainer/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pyside2.QtAxContainer — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/QtCore/index.html b/autoapi/koapy/compat/pyside2/QtCore/index.html new file mode 100644 index 00000000..544e900b --- /dev/null +++ b/autoapi/koapy/compat/pyside2/QtCore/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pyside2.QtCore — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/QtGui/index.html b/autoapi/koapy/compat/pyside2/QtGui/index.html new file mode 100644 index 00000000..e8645063 --- /dev/null +++ b/autoapi/koapy/compat/pyside2/QtGui/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pyside2.QtGui — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/QtNetwork/index.html b/autoapi/koapy/compat/pyside2/QtNetwork/index.html new file mode 100644 index 00000000..dbe956bf --- /dev/null +++ b/autoapi/koapy/compat/pyside2/QtNetwork/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pyside2.QtNetwork — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/QtWidgets/index.html b/autoapi/koapy/compat/pyside2/QtWidgets/index.html new file mode 100644 index 00000000..60e26847 --- /dev/null +++ b/autoapi/koapy/compat/pyside2/QtWidgets/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pyside2.QtWidgets — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pyside2/index.html b/autoapi/koapy/compat/pyside2/index.html new file mode 100644 index 00000000..a1aa036f --- /dev/null +++ b/autoapi/koapy/compat/pyside2/index.html @@ -0,0 +1,236 @@ + + + + + + + + + koapy.compat.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.compat.pyside2

+
+

Submodules

+ +
+
+

Package Contents

+
+

Functions

+ ++++ + + + + + +

get_logger(name=None)

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + +

config

debug

logger

QT_QPA_PLATFORM_PLUGIN_PATH

+
+
+koapy.compat.pyside2.config[source]
+
+ +
+
+koapy.compat.pyside2.debug = False[source]
+
+ +
+
+koapy.compat.pyside2.get_logger(name=None)[source]
+
+ +
+
+koapy.compat.pyside2.logger[source]
+
+ +
+
+koapy.compat.pyside2.QT_QPA_PLATFORM_PLUGIN_PATH[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pywinauto/findwindows/index.html b/autoapi/koapy/compat/pywinauto/findwindows/index.html new file mode 100644 index 00000000..19e9b6fa --- /dev/null +++ b/autoapi/koapy/compat/pywinauto/findwindows/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pywinauto.findwindows — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pywinauto/importlib/index.html b/autoapi/koapy/compat/pywinauto/importlib/index.html new file mode 100644 index 00000000..84c5786d --- /dev/null +++ b/autoapi/koapy/compat/pywinauto/importlib/index.html @@ -0,0 +1,234 @@ + + + + + + + + + koapy.compat.pywinauto.importlib — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.compat.pywinauto.importlib

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

PyWinAutoFinder

Abstract base class for import finders on sys.meta_path.

PyWinAutoLoader

Abstract base class for import loaders.

+
+
+class koapy.compat.pywinauto.importlib.PyWinAutoFinder[source]
+

Bases: importlib.abc.MetaPathFinder

+

Abstract base class for import finders on sys.meta_path.

+
+
+find_spec(self, fullname, path, target=None)[source]
+
+ +
+
+classmethod register(cls)[source]
+
+ +
+
+classmethod unregister(cls)[source]
+
+ +
+ +
+
+class koapy.compat.pywinauto.importlib.PyWinAutoLoader[source]
+

Bases: importlib.abc.Loader

+

Abstract base class for import loaders.

+
+
+set_sys_coinit_flags(self)[source]
+
+ +
+
+reset_sys_coinit_flags(self)[source]
+
+ +
+
+create_module(self, spec)[source]
+

Return a module to initialize and into which to load.

+

This method should raise ImportError if anything prevents it +from creating a new module. It may return None to indicate +that the spec should create the new module.

+
+ +
+
+exec_module(self, module)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pywinauto/index.html b/autoapi/koapy/compat/pywinauto/index.html new file mode 100644 index 00000000..bf7df9b5 --- /dev/null +++ b/autoapi/koapy/compat/pywinauto/index.html @@ -0,0 +1,208 @@ + + + + + + + + + koapy.compat.pywinauto — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.compat.pywinauto

+
+

Submodules

+ +
+
+

Package Contents

+
+

Classes

+ ++++ + + + + + +

PyWinAutoFinder

Abstract base class for import finders on sys.meta_path.

+
+
+class koapy.compat.pywinauto.PyWinAutoFinder[source]
+

Bases: importlib.abc.MetaPathFinder

+

Abstract base class for import finders on sys.meta_path.

+
+
+find_spec(self, fullname, path, target=None)
+
+ +
+
+classmethod register(cls)
+
+ +
+
+classmethod unregister(cls)
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/compat/pywinauto/timings/index.html b/autoapi/koapy/compat/pywinauto/timings/index.html new file mode 100644 index 00000000..edaf6ec7 --- /dev/null +++ b/autoapi/koapy/compat/pywinauto/timings/index.html @@ -0,0 +1,161 @@ + + + + + + + + + koapy.compat.pywinauto.timings — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/config/index.html b/autoapi/koapy/config/index.html new file mode 100644 index 00000000..521b1b4c --- /dev/null +++ b/autoapi/koapy/config/index.html @@ -0,0 +1,436 @@ + + + + + + + + + koapy.config — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.config

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

read_config(filename: Optional[Union[os.PathLike, str]] = None, encoding: Optional[str] = None) → Config

config_from_dict(dictionary: Mapping[str, Any]) → Config

find_user_config_file_in(searching_directory: Optional[Union[os.PathLike, str]] = None) → Optional[pathlib.Path]

find_user_config_file_from(starting_directory: Optional[Union[os.PathLike, str]] = None) → Optional[pathlib.Path]

set_user_config(c: Config) → Config

initialize_config_from_given_path(filename: Optional[Union[os.PathLike, str]] = None) → bool

initialize_config_from_expected_paths() → bool

get_config() → Config

get_user_config() → Config

dump_config(config: Config, compact: bool = False, indent: int = 4) → str

save_config(filename: Union[os.PathLike, str], config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None)

save_user_config(filename: Optional[Union[os.PathLike, str]] = None, user_config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None)

get_executable_from_conda_envname(envname: str) → str

get_executable_from_conda_envpath(envpath: str) → str

get_executable_from_executable_config(executable_config: Config) → Optional[str]

get_32bit_executable() → Optional[str]

get_64bit_executable() → Optional[str]

+
+
+

Attributes

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Config

default_config_filename

default_config_file_directory

default_config_filepath

current_working_directory

home_directory

default_user_config_filename

user_config_filename_cadidates

default_user_config_filepath

default_encoding

default_config

empty_config

user_config

config

debug

+
+
+koapy.config.Config[source]
+
+ +
+
+koapy.config.default_config_filename = config.conf[source]
+
+ +
+
+koapy.config.default_config_file_directory[source]
+
+ +
+
+koapy.config.default_config_filepath[source]
+
+ +
+
+koapy.config.current_working_directory[source]
+
+ +
+
+koapy.config.home_directory[source]
+
+ +
+
+koapy.config.default_user_config_filename = koapy.conf[source]
+
+ +
+
+koapy.config.user_config_filename_cadidates[source]
+
+ +
+
+koapy.config.default_user_config_filepath[source]
+
+ +
+
+koapy.config.default_encoding = utf-8[source]
+
+ +
+
+koapy.config.read_config(filename: Optional[Union[os.PathLike, str]] = None, encoding: Optional[str] = None) → Config[source]
+
+ +
+
+koapy.config.config_from_dict(dictionary: Mapping[str, Any]) → Config[source]
+
+ +
+
+koapy.config.default_config[source]
+
+ +
+
+koapy.config.find_user_config_file_in(searching_directory: Optional[Union[os.PathLike, str]] = None) → Optional[pathlib.Path][source]
+
+ +
+
+koapy.config.find_user_config_file_from(starting_directory: Optional[Union[os.PathLike, str]] = None) → Optional[pathlib.Path][source]
+
+ +
+
+koapy.config.empty_config[source]
+
+ +
+
+koapy.config.user_config[source]
+
+ +
+
+koapy.config.config[source]
+
+ +
+
+koapy.config.set_user_config(c: Config) → Config[source]
+
+ +
+
+koapy.config.initialize_config_from_given_path(filename: Optional[Union[os.PathLike, str]] = None) → bool[source]
+
+ +
+
+koapy.config.initialize_config_from_expected_paths() → bool[source]
+
+ +
+
+koapy.config.get_config() → Config[source]
+
+ +
+
+koapy.config.get_user_config() → Config[source]
+
+ +
+
+koapy.config.debug = False[source]
+
+ +
+
+koapy.config.dump_config(config: Config, compact: bool = False, indent: int = 4) → str[source]
+
+ +
+
+koapy.config.save_config(filename: Union[os.PathLike, str], config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None)[source]
+
+ +
+
+koapy.config.save_user_config(filename: Optional[Union[os.PathLike, str]] = None, user_config: Optional[Config] = None, compact: bool = False, indent: int = 4, encoding: Optional[str] = None)[source]
+
+ +
+
+koapy.config.get_executable_from_conda_envname(envname: str) → str[source]
+
+ +
+
+koapy.config.get_executable_from_conda_envpath(envpath: str) → str[source]
+
+ +
+
+koapy.config.get_executable_from_executable_config(executable_config: Config) → Optional[str][source]
+
+ +
+
+koapy.config.get_32bit_executable() → Optional[str][source]
+
+ +
+
+koapy.config.get_64bit_executable() → Optional[str][source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/index.html b/autoapi/koapy/index.html new file mode 100644 index 00000000..fc5a6e17 --- /dev/null +++ b/autoapi/koapy/index.html @@ -0,0 +1,298 @@ + + + + + + + + + koapy — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy

+

Top-level package for KOAPY.

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/builtin/index.html b/autoapi/koapy/utils/builtin/index.html new file mode 100644 index 00000000..24e452ff --- /dev/null +++ b/autoapi/koapy/utils/builtin/index.html @@ -0,0 +1,181 @@ + + + + + + + + + koapy.utils.builtin — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.builtin

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

dir_public(*args)

+
+
+koapy.utils.builtin.dir_public(*args)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/ctypes/index.html b/autoapi/koapy/utils/ctypes/index.html new file mode 100644 index 00000000..8ae72c3e --- /dev/null +++ b/autoapi/koapy/utils/ctypes/index.html @@ -0,0 +1,181 @@ + + + + + + + + + koapy.utils.ctypes — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.ctypes

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

is_admin()

+
+
+koapy.utils.ctypes.is_admin()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.html b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.html new file mode 100644 index 00000000..4e3f0202 --- /dev/null +++ b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.html @@ -0,0 +1,218 @@ + + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.data.KrxHistoricalDailyPriceDataDownloader

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KrxHistoricalDailyPriceDataDownloader

+
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataDownloader.KrxHistoricalDailyPriceDataDownloader[source]
+
+
+get_stocks(self)[source]
+
+ +
+
+get_stocks_delisted(self)[source]
+
+ +
+
+property stocks(self)[source]
+
+ +
+
+property stocks_delisted(self)[source]
+
+ +
+
+get_full_code(self, symbol)[source]
+
+ +
+
+get_name(self, symbol)[source]
+
+ +
+
+download(self, symbol, start_date=None, end_date=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.html b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.html new file mode 100644 index 00000000..130a46ba --- /dev/null +++ b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.html @@ -0,0 +1,213 @@ + + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KrxHistoricalDailyPriceDataForBacktestLoader

+
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader.KrxHistoricalDailyPriceDataForBacktestLoader(filename, library=None)[source]
+
+
+classmethod get_adjust_ratios(cls, data, sort=True)[source]
+
+ +
+
+classmethod adjust_data(cls, data, sort=True)[source]
+
+ +
+
+get_symbols(self)[source]
+
+ +
+
+update(self, download=False, progress_bar=False)[source]
+
+ +
+
+load(self, symbol, start_time=None, end_time=None)[source]
+
+ +
+
+load_as_cursor(self, symbol, start_time=None, end_time=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.html b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.html new file mode 100644 index 00000000..e199174b --- /dev/null +++ b/autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.html @@ -0,0 +1,213 @@ + + + + + + + + + koapy.utils.data.KrxHistoricalDailyPriceDataLoader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.data.KrxHistoricalDailyPriceDataLoader

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

KrxHistoricalDailyPriceDataLoader

+
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataLoader.KrxHistoricalDailyPriceDataLoader(filename, library=None, library_delisted=None)[source]
+
+
+property symbols(self)[source]
+
+ +
+
+property symbols_delisted(self)[source]
+
+ +
+
+load_from_database(self, symbol, is_delisted=None)[source]
+
+ +
+
+load_or_download(self, symbol, is_delisted=None, start_date=None, end_date=None)[source]
+
+ +
+
+load(self, symbol, is_delisted=None, start_date=None, end_date=None, download=True)[source]
+
+ +
+
+update(self, progress_bar=False)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.html b/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.html new file mode 100644 index 00000000..e95fad9b --- /dev/null +++ b/autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.html @@ -0,0 +1,188 @@ + + + + + + + + + koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

YahooFinanceKrxHistoricalDailyPriceDataDownloader

+
+
+class koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader.YahooFinanceKrxHistoricalDailyPriceDataDownloader[source]
+
+
+download(self, symbol, start_date=None, end_date=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/data/index.html b/autoapi/koapy/utils/data/index.html new file mode 100644 index 00000000..6e4a0afb --- /dev/null +++ b/autoapi/koapy/utils/data/index.html @@ -0,0 +1,303 @@ + + + + + + + + + koapy.utils.data — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.data

+
+

Submodules

+ +
+
+

Package Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

KrxHistoricalDailyPriceDataDownloader

KrxHistoricalDailyPriceDataForBacktestLoader

KrxHistoricalDailyPriceDataLoader

+
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataDownloader
+
+
+get_stocks(self)
+
+ +
+
+get_stocks_delisted(self)
+
+ +
+
+property stocks(self)
+
+ +
+
+property stocks_delisted(self)
+
+ +
+
+get_full_code(self, symbol)
+
+ +
+
+get_name(self, symbol)
+
+ +
+
+download(self, symbol, start_date=None, end_date=None)
+
+ +
+ +
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader(filename, library=None)
+
+
+classmethod get_adjust_ratios(cls, data, sort=True)
+
+ +
+
+classmethod adjust_data(cls, data, sort=True)
+
+ +
+
+get_symbols(self)
+
+ +
+
+update(self, download=False, progress_bar=False)
+
+ +
+
+load(self, symbol, start_time=None, end_time=None)
+
+ +
+
+load_as_cursor(self, symbol, start_time=None, end_time=None)
+
+ +
+ +
+
+class koapy.utils.data.KrxHistoricalDailyPriceDataLoader(filename, library=None, library_delisted=None)
+
+
+property symbols(self)
+
+ +
+
+property symbols_delisted(self)
+
+ +
+
+load_from_database(self, symbol, is_delisted=None)
+
+ +
+
+load_or_download(self, symbol, is_delisted=None, start_date=None, end_date=None)
+
+ +
+
+load(self, symbol, is_delisted=None, start_date=None, end_date=None, download=True)
+
+ +
+
+update(self, progress_bar=False)
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/datetime/index.html b/autoapi/koapy/utils/datetime/index.html new file mode 100644 index 00000000..753abb60 --- /dev/null +++ b/autoapi/koapy/utils/datetime/index.html @@ -0,0 +1,189 @@ + + + + + + + + + koapy.utils.datetime — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.datetime

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + +

is_naive(dt)

localize(dt, tz)

+
+
+koapy.utils.datetime.is_naive(dt)[source]
+
+ +
+
+koapy.utils.datetime.localize(dt, tz)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/exchange_calendars/index.html b/autoapi/koapy/utils/exchange_calendars/index.html new file mode 100644 index 00000000..245374d2 --- /dev/null +++ b/autoapi/koapy/utils/exchange_calendars/index.html @@ -0,0 +1,224 @@ + + + + + + + + + koapy.utils.exchange_calendars — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.exchange_calendars

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + +

is_currently_in_session() → bool

get_last_session_date() → pandas.Timestamp

+
+
+

Attributes

+ ++++ + + + + + + + + + + + +

name

calendar

day

+
+
+koapy.utils.exchange_calendars.name = XKRX[source]
+
+ +
+
+koapy.utils.exchange_calendars.calendar[source]
+
+ +
+
+koapy.utils.exchange_calendars.day[source]
+
+ +
+
+koapy.utils.exchange_calendars.is_currently_in_session() → bool[source]
+
+ +
+
+koapy.utils.exchange_calendars.get_last_session_date() → pandas.Timestamp[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/grpc/index.html b/autoapi/koapy/utils/grpc/index.html new file mode 100644 index 00000000..60f703e0 --- /dev/null +++ b/autoapi/koapy/utils/grpc/index.html @@ -0,0 +1,205 @@ + + + + + + + + + koapy.utils.grpc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.grpc

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + +

warn_on_rpc_error_context()

warn_on_rpc_error(stream)

cancel_after(stream, after)

pprint_message(message)

+
+
+koapy.utils.grpc.warn_on_rpc_error_context()[source]
+
+ +
+
+koapy.utils.grpc.warn_on_rpc_error(stream)[source]
+
+ +
+
+koapy.utils.grpc.cancel_after(stream, after)[source]
+
+ +
+
+koapy.utils.grpc.pprint_message(message)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/index.html b/autoapi/koapy/utils/index.html new file mode 100644 index 00000000..3d886f13 --- /dev/null +++ b/autoapi/koapy/utils/index.html @@ -0,0 +1,241 @@ + + + + + + + + + koapy.utils — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils

+
+

Subpackages

+ +
+
+

Submodules

+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/itertools/index.html b/autoapi/koapy/utils/itertools/index.html new file mode 100644 index 00000000..99bb44b7 --- /dev/null +++ b/autoapi/koapy/utils/itertools/index.html @@ -0,0 +1,181 @@ + + + + + + + + + koapy.utils.itertools — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.itertools

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

chunk(iterable, n)

+
+
+koapy.utils.itertools.chunk(iterable, n)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/Logging/index.html b/autoapi/koapy/utils/logging/Logging/index.html new file mode 100644 index 00000000..4e04d285 --- /dev/null +++ b/autoapi/koapy/utils/logging/Logging/index.html @@ -0,0 +1,252 @@ + + + + + + + + + koapy.utils.logging.Logging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.Logging

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

LoggingMeta

Logging

+
+
+class koapy.utils.logging.Logging.LoggingMeta(cls, clsname, bases, dct)[source]
+

Bases: type

+
+
+get_logger(cls, name=None)[source]
+
+ +
+
+get_class_logger(cls)[source]
+
+ +
+
+get_module_logger(cls)[source]
+
+ +
+
+get_package_logger(cls)[source]
+
+ +
+
+property logger(cls)[source]
+
+ +
+
+verbosity_to_loglevel(cls, verbosity)[source]
+
+ +
+
+loglevel_to_verbosity(cls, loglevel)[source]
+
+ +
+
+set_loglevel(cls, loglevel=logging.WARNING)[source]
+
+ +
+
+set_verbosity(cls, verbosity=0)[source]
+
+ +
+
+get_loglevel(cls)[source]
+
+ +
+
+get_verbosity(cls)[source]
+
+ +
+ +
+
+class koapy.utils.logging.Logging.Logging[source]
+
+
+property logger(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/index.html b/autoapi/koapy/utils/logging/index.html new file mode 100644 index 00000000..ca7dd97b --- /dev/null +++ b/autoapi/koapy/utils/logging/index.html @@ -0,0 +1,287 @@ + + + + + + + + + koapy.utils.logging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging

+
+

Subpackages

+ +
+
+

Submodules

+ +
+
+

Package Contents

+
+

Classes

+ ++++ + + + + + +

Logging

+
+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +

get_logger(name=None)

verbosity_to_loglevel(verbosity)

loglevel_to_verbosity(loglevel)

get_package_logger()

set_loglevel(loglevel)

set_verbosity(verbosity)

get_loglevel()

get_verbosity()

+
+
+class koapy.utils.logging.Logging
+
+
+property logger(self)
+
+ +
+ +
+
+koapy.utils.logging.get_logger(name=None)[source]
+
+ +
+
+koapy.utils.logging.verbosity_to_loglevel(verbosity)[source]
+
+ +
+
+koapy.utils.logging.loglevel_to_verbosity(loglevel)[source]
+
+ +
+
+koapy.utils.logging.get_package_logger()[source]
+
+ +
+
+koapy.utils.logging.set_loglevel(loglevel)[source]
+
+ +
+
+koapy.utils.logging.set_verbosity(verbosity)[source]
+
+ +
+
+koapy.utils.logging.get_loglevel()[source]
+
+ +
+
+koapy.utils.logging.get_verbosity()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.html b/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.html new file mode 100644 index 00000000..e05fb6f2 --- /dev/null +++ b/autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.html @@ -0,0 +1,195 @@ + + + + + + + + + koapy.utils.logging.pyside2.QAbstractSocketLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.pyside2.QAbstractSocketLogging

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QAbstractSocketLoggingMeta

QAbstractSocketLogging

+
+
+class koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLoggingMeta(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(QAbstractSocket)

+
+ +
+
+class koapy.utils.logging.pyside2.QAbstractSocketLogging.QAbstractSocketLogging(*args, **kwargs)[source]
+

Bases: koapy.compat.pyside2.QtNetwork.QAbstractSocket, koapy.utils.logging.Logging.Logging

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.html b/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.html new file mode 100644 index 00000000..16891b10 --- /dev/null +++ b/autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.html @@ -0,0 +1,195 @@ + + + + + + + + + koapy.utils.logging.pyside2.QObjectLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.pyside2.QObjectLogging

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QObjectLoggingMeta

QObjectLogging

+
+
+class koapy.utils.logging.pyside2.QObjectLogging.QObjectLoggingMeta(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(QObject)

+
+ +
+
+class koapy.utils.logging.pyside2.QObjectLogging.QObjectLogging(*args, **kwargs)[source]
+

Bases: koapy.compat.pyside2.QtCore.QObject, koapy.utils.logging.Logging.Logging

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.html b/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.html new file mode 100644 index 00000000..2b3c7192 --- /dev/null +++ b/autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.html @@ -0,0 +1,195 @@ + + + + + + + + + koapy.utils.logging.pyside2.QThreadLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.pyside2.QThreadLogging

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QThreadLoggingMeta

QThreadLogging

+
+
+class koapy.utils.logging.pyside2.QThreadLogging.QThreadLoggingMeta(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(QThread)

+
+ +
+
+class koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging(*args, **kwargs)[source]
+

Bases: koapy.compat.pyside2.QtCore.QThread, koapy.utils.logging.Logging.Logging

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.html b/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.html new file mode 100644 index 00000000..ca21ed29 --- /dev/null +++ b/autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.html @@ -0,0 +1,195 @@ + + + + + + + + + koapy.utils.logging.pyside2.QWidgetLogging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.pyside2.QWidgetLogging

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

QWidgetLoggingMeta

QWidgetLogging

+
+
+class koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLoggingMeta(cls, clsname, bases, dct)[source]
+

Bases: type(Logging), type(QWidget)

+
+ +
+
+class koapy.utils.logging.pyside2.QWidgetLogging.QWidgetLogging(*args, **kwargs)[source]
+

Bases: koapy.compat.pyside2.QtWidgets.QWidget, koapy.utils.logging.Logging.Logging

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/pyside2/index.html b/autoapi/koapy/utils/logging/pyside2/index.html new file mode 100644 index 00000000..30005224 --- /dev/null +++ b/autoapi/koapy/utils/logging/pyside2/index.html @@ -0,0 +1,172 @@ + + + + + + + + + koapy.utils.logging.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.html b/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.html new file mode 100644 index 00000000..90b32ef6 --- /dev/null +++ b/autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.html @@ -0,0 +1,189 @@ + + + + + + + + + koapy.utils.logging.tqdm.TqdmStreamHandler — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.logging.tqdm.TqdmStreamHandler

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

TqdmStreamHandler

A handler class which writes logging records, appropriately formatted,

+
+
+class koapy.utils.logging.tqdm.TqdmStreamHandler.TqdmStreamHandler(stream=None)[source]
+

Bases: logging.StreamHandler

+

A handler class which writes logging records, appropriately formatted, +to a stream. Note that this class does not close the stream, as +sys.stdout or sys.stderr may be used.

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/logging/tqdm/index.html b/autoapi/koapy/utils/logging/tqdm/index.html new file mode 100644 index 00000000..fcb8cbf8 --- /dev/null +++ b/autoapi/koapy/utils/logging/tqdm/index.html @@ -0,0 +1,169 @@ + + + + + + + + + koapy.utils.logging.tqdm — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/messaging/DiscordMessenger/index.html b/autoapi/koapy/utils/messaging/DiscordMessenger/index.html new file mode 100644 index 00000000..dccd135b --- /dev/null +++ b/autoapi/koapy/utils/messaging/DiscordMessenger/index.html @@ -0,0 +1,203 @@ + + + + + + + + + koapy.utils.messaging.DiscordMessenger — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.messaging.DiscordMessenger

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + +

DiscordWebhookMessenger

DoItYourselfDiscordWebhookMessenger

+
+
+class koapy.utils.messaging.DiscordMessenger.DiscordWebhookMessenger(url=None)[source]
+

Bases: koapy.utils.messaging.Messenger.Messenger

+
+
+send_message(self, content)[source]
+
+ +
+ +
+
+class koapy.utils.messaging.DiscordMessenger.DoItYourselfDiscordWebhookMessenger(url=None)[source]
+

Bases: koapy.utils.messaging.Messenger.Messenger

+
+
+send_message(self, content)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/messaging/Messenger/index.html b/autoapi/koapy/utils/messaging/Messenger/index.html new file mode 100644 index 00000000..c33beaec --- /dev/null +++ b/autoapi/koapy/utils/messaging/Messenger/index.html @@ -0,0 +1,189 @@ + + + + + + + + + koapy.utils.messaging.Messenger — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.messaging.Messenger

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Messenger

+
+
+class koapy.utils.messaging.Messenger.Messenger[source]
+

Bases: abc.ABC

+
+
+abstract send_message(self, content)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/messaging/index.html b/autoapi/koapy/utils/messaging/index.html new file mode 100644 index 00000000..3dd5a55d --- /dev/null +++ b/autoapi/koapy/utils/messaging/index.html @@ -0,0 +1,168 @@ + + + + + + + + + koapy.utils.messaging — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/networking/index.html b/autoapi/koapy/utils/networking/index.html new file mode 100644 index 00000000..90763dda --- /dev/null +++ b/autoapi/koapy/utils/networking/index.html @@ -0,0 +1,197 @@ + + + + + + + + + koapy.utils.networking — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.networking

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

find_free_port_for_host(host)

get_free_localhost_port()

is_in_private_network(host)

+
+
+koapy.utils.networking.find_free_port_for_host(host)[source]
+
+ +
+
+koapy.utils.networking.get_free_localhost_port()[source]
+
+ +
+
+koapy.utils.networking.is_in_private_network(host)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/notimplemented/index.html b/autoapi/koapy/utils/notimplemented/index.html new file mode 100644 index 00000000..c0a49182 --- /dev/null +++ b/autoapi/koapy/utils/notimplemented/index.html @@ -0,0 +1,197 @@ + + + + + + + + + koapy.utils.notimplemented — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.notimplemented

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

notimplemented(func)

isnotimplemented(func)

isimplemented(func)

+
+
+koapy.utils.notimplemented.notimplemented(func)[source]
+
+ +
+
+koapy.utils.notimplemented.isnotimplemented(func)[source]
+
+ +
+
+koapy.utils.notimplemented.isimplemented(func)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/platform/index.html b/autoapi/koapy/utils/platform/index.html new file mode 100644 index 00000000..57d37c62 --- /dev/null +++ b/autoapi/koapy/utils/platform/index.html @@ -0,0 +1,197 @@ + + + + + + + + + koapy.utils.platform — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.platform

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + +

is_windows()

is_32bit()

is_64bit()

+
+
+koapy.utils.platform.is_windows()[source]
+
+ +
+
+koapy.utils.platform.is_32bit()[source]
+
+ +
+
+koapy.utils.platform.is_64bit()[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/pywin32/index.html b/autoapi/koapy/utils/pywin32/index.html new file mode 100644 index 00000000..0e694a54 --- /dev/null +++ b/autoapi/koapy/utils/pywin32/index.html @@ -0,0 +1,264 @@ + + + + + + + + + koapy.utils.pywin32 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.pywin32

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + +

IsPyIID(value) → TypeGuard[PyIID]

IsPyITypeLib(value) → TypeGuard[PyITypeLib]

IsPyIIDLike(value) → TypeGuard[PyIIDLike]

GetTypelibSpecs(iid: PyIIDLike) → List[win32com.client.selecttlb.TypelibSpec]

GetLatestTypelibSpec(specs: Union[Sequence[win32com.client.selecttlb.TypelibSpec], PyIIDLike]) → Optional[win32com.client.selecttlb.TypelibSpec]

LoadTypeLib(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike]) → Optional[PyITypeLib]

BuildOleItems(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike], tlb: Optional[PyITypeLib] = None) → Tuple[Dict[PyIID, win32com.client.genpy.DispatchItem], Dict[PyIID, win32com.client.genpy.EnumerationItem], Dict[PyIID, win32com.client.genpy.RecordItem], Dict[PyIID, win32com.client.genpy.VTableItem]]

+
+
+

Attributes

+ ++++ + + + + + + + + + + + +

PyIID

PyITypeLib

PyIIDLike

+
+
+koapy.utils.pywin32.PyIID[source]
+
+ +
+
+koapy.utils.pywin32.PyITypeLib = PyITypeLib[source]
+
+ +
+
+koapy.utils.pywin32.PyIIDLike[source]
+
+ +
+
+koapy.utils.pywin32.IsPyIID(value) → TypeGuard[PyIID][source]
+
+ +
+
+koapy.utils.pywin32.IsPyITypeLib(value) → TypeGuard[PyITypeLib][source]
+
+ +
+
+koapy.utils.pywin32.IsPyIIDLike(value) → TypeGuard[PyIIDLike][source]
+
+ +
+
+koapy.utils.pywin32.GetTypelibSpecs(iid: PyIIDLike) → List[win32com.client.selecttlb.TypelibSpec][source]
+
+ +
+
+koapy.utils.pywin32.GetLatestTypelibSpec(specs: Union[Sequence[win32com.client.selecttlb.TypelibSpec], PyIIDLike]) → Optional[win32com.client.selecttlb.TypelibSpec][source]
+
+ +
+
+koapy.utils.pywin32.LoadTypeLib(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike]) → Optional[PyITypeLib][source]
+
+ +
+
+koapy.utils.pywin32.BuildOleItems(spec: Union[win32com.client.selecttlb.TypelibSpec, PyIIDLike], tlb: Optional[PyITypeLib] = None) → Tuple[Dict[PyIID, win32com.client.genpy.DispatchItem], Dict[PyIID, win32com.client.genpy.EnumerationItem], Dict[PyIID, win32com.client.genpy.RecordItem], Dict[PyIID, win32com.client.genpy.VTableItem]][source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/rate_limiting/RateLimiter/index.html b/autoapi/koapy/utils/rate_limiting/RateLimiter/index.html new file mode 100644 index 00000000..2b4811d8 --- /dev/null +++ b/autoapi/koapy/utils/rate_limiting/RateLimiter/index.html @@ -0,0 +1,251 @@ + + + + + + + + + koapy.utils.rate_limiting.RateLimiter — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.rate_limiting.RateLimiter

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

RateLimiter

TimeWindowRateLimiter

CompositeTimeWindowRateLimiter

+
+
+class koapy.utils.rate_limiting.RateLimiter.RateLimiter[source]
+
+
+check_sleep_seconds(self, *args, **kwargs)[source]
+
+ +
+
+add_call_history(self, *args, **kwargs)[source]
+
+ +
+
+sleep_if_necessary(self, *args, **kwargs)[source]
+
+ +
+
+wrap(self, func)[source]
+
+ +
+ +
+
+class koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter(period, calls)[source]
+

Bases: RateLimiter, koapy.utils.logging.Logging.Logging

+
+
+check_sleep_seconds(self, *args, **kwargs)[source]
+
+ +
+
+add_call_history(self, *args, **kwargs)[source]
+
+ +
+
+sleep_if_necessary(self, *args, **kwargs)[source]
+
+ +
+ +
+
+class koapy.utils.rate_limiting.RateLimiter.CompositeTimeWindowRateLimiter(limiters: List[RateLimiter])[source]
+

Bases: RateLimiter

+
+
+check_sleep_seconds(self, *args, **kwargs)[source]
+
+ +
+
+add_call_history(self, *args, **kwargs)[source]
+
+ +
+
+sleep_if_necessary(self, *args, **kwargs)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/rate_limiting/index.html b/autoapi/koapy/utils/rate_limiting/index.html new file mode 100644 index 00000000..adfe80c8 --- /dev/null +++ b/autoapi/koapy/utils/rate_limiting/index.html @@ -0,0 +1,178 @@ + + + + + + + + + koapy.utils.rate_limiting — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.html b/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.html new file mode 100644 index 00000000..b012cefe --- /dev/null +++ b/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.html @@ -0,0 +1,299 @@ + + + + + + + + + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + + + + + + + +

QRateLimitedExecutorRunnable

QRateLimitedExecutorDecoratedFunction

QRateLimitedExecutor

This is an abstract base class for concrete asynchronous executors.

+
+
+class koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorRunnable(limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, future: concurrent.futures.Future, fn: Callable[Ellipsis, Any], args: Union[Tuple[Any], List[Any]], kwargs: Dict[str, Any])[source]
+
+
+check_sleep_seconds(self)[source]
+
+ +
+
+add_call_history(self)[source]
+
+ +
+
+sleep_if_necessary(self)[source]
+
+ +
+
+run(self)[source]
+
+ +
+
+cancel(self)[source]
+
+ +
+
+result(self)[source]
+
+ +
+ +
+
+class koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorDecoratedFunction(func, limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, executor: concurrent.futures.Executor)[source]
+
+
+call(self, *args, **kwargs)[source]
+
+ +
+
+async_call(self, *args, **kwargs)[source]
+
+ +
+ +
+
+class koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutor(limiter: koapy.utils.rate_limiting.RateLimiter.RateLimiter, parent: Optional[koapy.compat.pyside2.QtCore.QObject] = None)[source]
+

Bases: koapy.utils.logging.pyside2.QThreadLogging.QThreadLogging, concurrent.futures.Executor

+

This is an abstract base class for concrete asynchronous executors.

+
+
+readyRunnable[source]
+
+ +
+
+run(self)[source]
+
+ +
+
+onReadyRunnable(self, runnable: QRateLimitedExecutorRunnable)[source]
+
+ +
+
+submit(self, fn: Callable[Ellipsis, Any], *args, **kwargs)[source]
+

Submits a callable to be executed with the given arguments.

+

Schedules the callable to be executed as fn(*args, **kwargs) and returns +a Future instance representing the execution of the callable.

+
+

System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst, line 73); backlink

+

Inline emphasis start-string without end-string.

+
+
+

System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst, line 73); backlink

+

Inline strong start-string without end-string.

+
+
+
Returns
+

A Future representing the given call.

+
+
+
+ +
+
+shutdown(self, wait: bool = True, cancel_futures: bool = False)[source]
+

Clean-up the resources associated with the Executor.

+

It is safe to call this method several times. Otherwise, no other +methods can be called after this one.

+
+
Parameters
+

wait – If True then shutdown will not return until all running +futures have finished executing and the resources used by the +executor have been reclaimed.

+
+
+
+ +
+
+wrap(self, func: Callable[Ellipsis, Any])[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/rate_limiting/pyside2/index.html b/autoapi/koapy/utils/rate_limiting/pyside2/index.html new file mode 100644 index 00000000..16939bec --- /dev/null +++ b/autoapi/koapy/utils/rate_limiting/pyside2/index.html @@ -0,0 +1,169 @@ + + + + + + + + + koapy.utils.rate_limiting.pyside2 — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/recursion/index.html b/autoapi/koapy/utils/recursion/index.html new file mode 100644 index 00000000..5de874d8 --- /dev/null +++ b/autoapi/koapy/utils/recursion/index.html @@ -0,0 +1,182 @@ + + + + + + + + + koapy.utils.recursion — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.recursion

+
+

Module Contents

+
+

Functions

+ ++++ + + + + + +

depth()

return recursion depth. 0 if no recursion

+
+
+koapy.utils.recursion.depth()[source]
+

return recursion depth. 0 if no recursion

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/serialization/index.html b/autoapi/koapy/utils/serialization/index.html new file mode 100644 index 00000000..68a92135 --- /dev/null +++ b/autoapi/koapy/utils/serialization/index.html @@ -0,0 +1,201 @@ + + + + + + + + + koapy.utils.serialization — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.serialization

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

JsonSerializable

+
+
+class koapy.utils.serialization.JsonSerializable[source]
+
+
+to_dict(self)[source]
+
+ +
+
+classmethod from_dict(cls, dic)[source]
+
+ +
+
+to_json(self, f=None, encoding=None)[source]
+
+ +
+
+classmethod from_json(cls, jsn, encoding=None)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/SQLiteFileLibrary/index.html b/autoapi/koapy/utils/store/SQLiteFileLibrary/index.html new file mode 100644 index 00000000..64dabf37 --- /dev/null +++ b/autoapi/koapy/utils/store/SQLiteFileLibrary/index.html @@ -0,0 +1,218 @@ + + + + + + + + + koapy.utils.store.SQLiteFileLibrary — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.SQLiteFileLibrary

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLiteFileLibrary

+
+
+class koapy.utils.store.SQLiteFileLibrary.SQLiteFileLibrary(filename)[source]
+
+
+list_symbols(self)[source]
+
+ +
+
+has_symbol(self, symbol)[source]
+
+ +
+
+write(self, symbol, data)[source]
+
+ +
+
+read_as_dataframe(self, symbol, time_column=None, start_time=None, end_time=None)[source]
+
+ +
+
+read_as_cursor(self, symbol, time_column=None, start_time=None, end_time=None)[source]
+
+ +
+
+read(self, *args, **kwargs)[source]
+
+ +
+
+delete(self, symbol)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/SQLiteStore/index.html b/autoapi/koapy/utils/store/SQLiteStore/index.html new file mode 100644 index 00000000..f9f74a5c --- /dev/null +++ b/autoapi/koapy/utils/store/SQLiteStore/index.html @@ -0,0 +1,213 @@ + + + + + + + + + koapy.utils.store.SQLiteStore — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.SQLiteStore

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLiteStore

+
+
+class koapy.utils.store.SQLiteStore.SQLiteStore(filename)[source]
+
+
+list_libraries(self)[source]
+
+ +
+
+library_exists(self, library)[source]
+
+ +
+
+initialize_library(self, library)[source]
+
+ +
+
+get_library(self, library)[source]
+
+ +
+
+get_or_create_library(self, library)[source]
+
+ +
+
+delete_library(self, library)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.html b/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.html new file mode 100644 index 00000000..6db0634f --- /dev/null +++ b/autoapi/koapy/utils/store/SQLiteStoreLibrary/index.html @@ -0,0 +1,238 @@ + + + + + + + + + koapy.utils.store.SQLiteStoreLibrary — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.SQLiteStoreLibrary

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SQLiteStoreLibrary

+
+
+class koapy.utils.store.SQLiteStoreLibrary.SQLiteStoreLibrary(store, library)[source]
+
+
+list_symbols(self, all_symbols=False, snapshot=None)[source]
+
+ +
+
+has_symbol(self, symbol)[source]
+
+ +
+
+list_versions(self, symbol=None, snapshot=None, latest_only=False)[source]
+
+ +
+
+write(self, symbol, data, metadata=None, prune_previous_version=True, **kwargs)[source]
+
+ +
+
+read_as_dataframe(self, symbol, as_of=None, time_column=None, start_time=None, end_time=None)[source]
+
+ +
+
+read_as_cursor(self, symbol, as_of=None, time_column=None, start_time=None, end_time=None)[source]
+
+ +
+
+read(self, *args, **kwargs)[source]
+
+ +
+
+delete(self, symbol)[source]
+
+ +
+
+list_snapshots(self)[source]
+
+ +
+
+snapshot(self, snapshot)[source]
+
+ +
+
+delete_snapshot(self, snapshot)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/index.html b/autoapi/koapy/utils/store/index.html new file mode 100644 index 00000000..56115a82 --- /dev/null +++ b/autoapi/koapy/utils/store/index.html @@ -0,0 +1,243 @@ + + + + + + + + + koapy.utils.store — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store

+
+

Subpackages

+ +
+
+

Submodules

+ +
+
+

Package Contents

+
+

Classes

+ ++++ + + + + + +

SQLiteStore

+
+
+class koapy.utils.store.SQLiteStore(filename)
+
+
+list_libraries(self)
+
+ +
+
+library_exists(self, library)
+
+ +
+
+initialize_library(self, library)
+
+ +
+
+get_library(self, library)
+
+ +
+
+get_or_create_library(self, library)
+
+ +
+
+delete_library(self, library)
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/misc/VersionedItem/index.html b/autoapi/koapy/utils/store/misc/VersionedItem/index.html new file mode 100644 index 00000000..f5762afd --- /dev/null +++ b/autoapi/koapy/utils/store/misc/VersionedItem/index.html @@ -0,0 +1,185 @@ + + + + + + + + + koapy.utils.store.misc.VersionedItem — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.misc.VersionedItem

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

VersionedItem

+
+
+class koapy.utils.store.misc.VersionedItem.VersionedItem(library, symbol, version, timestamp, data, metadata)[source]
+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/misc/index.html b/autoapi/koapy/utils/store/misc/index.html new file mode 100644 index 00000000..8603ec7b --- /dev/null +++ b/autoapi/koapy/utils/store/misc/index.html @@ -0,0 +1,169 @@ + + + + + + + + + koapy.utils.store.misc — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Base/index.html b/autoapi/koapy/utils/store/sqlalchemy/Base/index.html new file mode 100644 index 00000000..8e2fbb9e --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Base/index.html @@ -0,0 +1,171 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Base — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Base

+
+

Module Contents

+
+
+koapy.utils.store.sqlalchemy.Base.Base[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Library/index.html b/autoapi/koapy/utils/store/sqlalchemy/Library/index.html new file mode 100644 index 00000000..e9fd4841 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Library/index.html @@ -0,0 +1,246 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Library — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Library

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Library

+
+
+class koapy.utils.store.sqlalchemy.Library.Library[source]
+

Bases: koapy.utils.store.sqlalchemy.Base.Base

+
+
+id[source]
+
+ +
+
+name[source]
+
+ +
+
+symbols[source]
+
+ +
+
+snapshots[source]
+
+ +
+
+get_symbol(self, symbol, deleted=False)[source]
+
+ +
+
+get_or_create_symbol(self, symbol)[source]
+
+ +
+
+get_symbols(self, deleted=False)[source]
+
+ +
+
+get_versions(self, deleted=False)[source]
+
+ +
+
+get_latest_versions(self, deleted=False)[source]
+
+ +
+
+get_snapshot(self, snapshot)[source]
+
+ +
+
+create_snapshot(self, snapshot)[source]
+
+ +
+
+delete(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Session/index.html b/autoapi/koapy/utils/store/sqlalchemy/Session/index.html new file mode 100644 index 00000000..e7896b14 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Session/index.html @@ -0,0 +1,171 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Session — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Session

+
+

Module Contents

+
+
+koapy.utils.store.sqlalchemy.Session.Session[source]
+
+ +
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.html b/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.html new file mode 100644 index 00000000..2b15f4f9 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.html @@ -0,0 +1,236 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Snapshot — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Snapshot

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Snapshot

+
+
+class koapy.utils.store.sqlalchemy.Snapshot.Snapshot[source]
+

Bases: koapy.utils.store.sqlalchemy.Base.Base

+
+
+id[source]
+
+ +
+
+name[source]
+
+ +
+
+timestamp[source]
+
+ +
+
+library_id[source]
+
+ +
+
+library[source]
+
+ +
+
+versions[source]
+
+ +
+
+get_symbols(self)[source]
+
+ +
+
+get_versions(self)[source]
+
+ +
+
+get_version_of_symbol(self, symbol)[source]
+
+ +
+
+delete(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.html b/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.html new file mode 100644 index 00000000..7cdbecd8 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.html @@ -0,0 +1,206 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.SnapshotAssociation — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.SnapshotAssociation

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

SnapshotAssociation

+
+
+class koapy.utils.store.sqlalchemy.SnapshotAssociation.SnapshotAssociation[source]
+

Bases: koapy.utils.store.sqlalchemy.Base.Base

+
+
+snapshot_id[source]
+
+ +
+
+version_id[source]
+
+ +
+
+snapshot[source]
+
+ +
+
+version[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.html b/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.html new file mode 100644 index 00000000..7f22b37e --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.html @@ -0,0 +1,267 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Symbol — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Symbol

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Symbol

+
+
+class koapy.utils.store.sqlalchemy.Symbol.Symbol[source]
+

Bases: koapy.utils.store.sqlalchemy.Base.Base

+
+
+id[source]
+
+ +
+
+name[source]
+
+ +
+
+library_id[source]
+
+ +
+
+library[source]
+
+ +
+
+versions[source]
+
+ +
+
+get_versions(self, deleted=False)[source]
+

versions = self.versions +if not deleted:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst, line 53)

+

Unexpected indentation.

+
+
+

versions = [version for version in versions if not version.deleted]

+
+
+ +
+
+get_latest_version(self, deleted=False)[source]
+

versions = self.versions +if len(versions) == 0:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst, line 60)

+

Unexpected indentation.

+
+
+

raise NoResultFound

+
+
+

System Message: WARNING/2 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst, line 61)

+

Block quote ends without a blank line; unexpected unindent.

+
+

latest_version = self.versions[-1] +if not deleted and latest_version.deleted:

+
+

System Message: ERROR/3 (/home/runner/work/koapy/koapy/docs/source/autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst, line 63)

+

Unexpected indentation.

+
+
+

raise NoResultFound

+
+
+ +
+
+create_new_version(self, table_name=None, user_metadata=None, pandas_metadata=None, deleted=None)[source]
+
+ +
+
+get_version_by_number(self, version_number, deleted=False)[source]
+
+ +
+
+get_prunable_versions(self, keep_mins=120)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.html b/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.html new file mode 100644 index 00000000..b6b95570 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.html @@ -0,0 +1,378 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Timestamp — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Timestamp

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Timestamp

Allows the creation of types which add additional functionality

+
+
+class koapy.utils.store.sqlalchemy.Timestamp.Timestamp(*args, **kwargs)[source]
+

Bases: sqlalchemy.types.TypeDecorator

+

Allows the creation of types which add additional functionality +to an existing type.

+

This method is preferred to direct subclassing of SQLAlchemy’s +built-in types as it ensures that all required functionality of +the underlying type is kept in place.

+

Typical usage:

+
import sqlalchemy.types as types
+
+class MyType(types.TypeDecorator):
+    '''Prefixes Unicode values with "PREFIX:" on the way in and
+    strips it off on the way out.
+    '''
+
+    impl = types.Unicode
+
+    cache_ok = True
+
+    def process_bind_param(self, value, dialect):
+        return "PREFIX:" + value
+
+    def process_result_value(self, value, dialect):
+        return value[7:]
+
+    def copy(self, **kw):
+        return MyType(self.impl.length)
+
+
+

The class-level impl attribute is required, and can reference any +TypeEngine class. Alternatively, the load_dialect_impl +method can be used to provide different type classes based on the dialect +given; in this case, the impl variable can reference +TypeEngine as a placeholder.

+

The TypeDecorator.cache_ok class-level flag indicates if this +custom TypeDecorator is safe to be used as part of a cache key. +This flag defaults to None which will initially generate a warning +when the SQL compiler attempts to generate a cache key for a statement +that uses this type. If the TypeDecorator is not guaranteed +to produce the same bind/result behavior and SQL generation +every time, this flag should be set to False; otherwise if the +class produces the same behavior each time, it may be set to True. +See TypeDecorator.cache_ok for further notes on how this works.

+

Types that receive a Python type that isn’t similar to the ultimate type +used may want to define the TypeDecorator.coerce_compared_value +method. This is used to give the expression system a hint when coercing +Python objects into bind parameters within expressions. Consider this +expression:

+
mytable.c.somecol + datetime.date(2009, 5, 15)
+
+
+

Above, if “somecol” is an Integer variant, it makes sense that +we’re doing date arithmetic, where above is usually interpreted +by databases as adding a number of days to the given date. +The expression system does the right thing by not attempting to +coerce the “date()” value into an integer-oriented bind parameter.

+

However, in the case of TypeDecorator, we are usually changing an +incoming Python type to something new - TypeDecorator by default will +“coerce” the non-typed side to be the same type as itself. Such as below, +we define an “epoch” type that stores a date value as an integer:

+
class MyEpochType(types.TypeDecorator):
+    impl = types.Integer
+
+    epoch = datetime.date(1970, 1, 1)
+
+    def process_bind_param(self, value, dialect):
+        return (value - self.epoch).days
+
+    def process_result_value(self, value, dialect):
+        return self.epoch + timedelta(days=value)
+
+
+

Our expression of somecol + date with the above type will coerce the +“date” on the right side to also be treated as MyEpochType.

+

This behavior can be overridden via the +coerce_compared_value method, which returns a type +that should be used for the value of the expression. Below we set it such +that an integer value will be treated as an Integer, and any other +value is assumed to be a date and will be treated as a MyEpochType:

+
def coerce_compared_value(self, op, value):
+    if isinstance(value, int):
+        return Integer()
+    else:
+        return self
+
+
+
+

Warning

+

Note that the behavior of coerce_compared_value is not inherited +by default from that of the base type. +If the TypeDecorator is augmenting a +type that requires special logic for certain types of operators, +this method must be overridden. A key example is when decorating +the _postgresql.JSON and _postgresql.JSONB types; +the default rules of TypeEngine.coerce_compared_value should +be used in order to deal with operators like index operations:

+
class MyJsonType(TypeDecorator):
+    impl = postgresql.JSON
+
+    cache_ok = True
+
+    def coerce_compared_value(self, op, value):
+        return self.impl.coerce_compared_value(op, value)
+
+
+

Without the above step, index operations such as mycol['foo'] +will cause the index value 'foo' to be JSON encoded.

+
+
+
+impl[source]
+
+ +
+
+cache_ok = True[source]
+
+ +
+
+signature[source]
+
+ +
+
+utc[source]
+
+ +
+
+local_timezone[source]
+
+ +
+
+classmethod is_naive(cls, value)[source]
+
+ +
+
+process_bind_param(self, value, dialect)[source]
+

Receive a bound parameter value to be converted.

+

Custom subclasses of _types.TypeDecorator should override +this method to provide custom behaviors for incoming data values. +This method is called at statement execution time and is passed +the literal Python data value which is to be associated with a bound +parameter in the statement.

+

The operation could be anything desired to perform custom +behavior, such as transforming or serializing data. +This could also be used as a hook for validating logic.

+
+
Parameters
+
    +
  • value – Data to operate upon, of any type expected by +this method in the subclass. Can be None.

  • +
  • dialect – the Dialect in use.

  • +
+
+
+
+

See also

+

types_typedecorator

+

_types.TypeDecorator.process_result_value

+
+
+ +
+
+process_result_value(self, value, dialect)[source]
+

Receive a result-row column value to be converted.

+

Custom subclasses of _types.TypeDecorator should override +this method to provide custom behaviors for data values +being received in result rows coming from the database. +This method is called at result fetching time and is passed +the literal Python data value that’s extracted from a database result +row.

+

The operation could be anything desired to perform custom +behavior, such as transforming or deserializing data.

+
+
Parameters
+
    +
  • value – Data to operate upon, of any type expected by +this method in the subclass. Can be None.

  • +
  • dialect – the Dialect in use.

  • +
+
+
+
+

See also

+

types_typedecorator

+

_types.TypeDecorator.process_bind_param

+
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/Version/index.html b/autoapi/koapy/utils/store/sqlalchemy/Version/index.html new file mode 100644 index 00000000..284d430f --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/Version/index.html @@ -0,0 +1,246 @@ + + + + + + + + + koapy.utils.store.sqlalchemy.Version — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.store.sqlalchemy.Version

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Version

+
+
+class koapy.utils.store.sqlalchemy.Version.Version[source]
+

Bases: koapy.utils.store.sqlalchemy.Base.Base

+
+
+id[source]
+
+ +
+
+version[source]
+
+ +
+
+table_name[source]
+
+ +
+
+user_metadata[source]
+
+ +
+
+pandas_metadata[source]
+
+ +
+
+deleted[source]
+
+ +
+
+timestamp[source]
+
+ +
+
+symbol_id[source]
+
+ +
+
+symbol[source]
+
+ +
+
+snapshots[source]
+
+ +
+
+get_snapshots(self)[source]
+
+ +
+
+delete(self)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/store/sqlalchemy/index.html b/autoapi/koapy/utils/store/sqlalchemy/index.html new file mode 100644 index 00000000..f0ee9d02 --- /dev/null +++ b/autoapi/koapy/utils/store/sqlalchemy/index.html @@ -0,0 +1,176 @@ + + + + + + + + + koapy.utils.store.sqlalchemy — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/subprocess/index.html b/autoapi/koapy/utils/subprocess/index.html new file mode 100644 index 00000000..db25eee3 --- /dev/null +++ b/autoapi/koapy/utils/subprocess/index.html @@ -0,0 +1,292 @@ + + + + + + + + + koapy.utils.subprocess — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.subprocess

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Popen

+
+
+

Functions

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

function_to_script(func)

function_to_subprocess_args(func, executable=None)

run_file(filename, *args, executable=None, **kwargs)

run_script(script, *args, executable=None, **kwargs)

run_function(function, *args, executable=None, **kwargs)

quote(s)

run_as_admin(cmd, cwd=None, check=True, wait=True)

create_job_object_for_cleanup()

make_process_die_when_parent_dies(pid)

+
+
+

Attributes

+ ++++ + + + + + + + + +

logger

job_handle

+
+
+koapy.utils.subprocess.logger[source]
+
+ +
+
+koapy.utils.subprocess.function_to_script(func)[source]
+
+ +
+
+koapy.utils.subprocess.function_to_subprocess_args(func, executable=None)[source]
+
+ +
+
+koapy.utils.subprocess.run_file(filename, *args, executable=None, **kwargs)[source]
+
+ +
+
+koapy.utils.subprocess.run_script(script, *args, executable=None, **kwargs)[source]
+
+ +
+
+koapy.utils.subprocess.run_function(function, *args, executable=None, **kwargs)[source]
+
+ +
+
+koapy.utils.subprocess.quote(s)[source]
+
+ +
+
+koapy.utils.subprocess.run_as_admin(cmd, cwd=None, check=True, wait=True)[source]
+
+ +
+
+koapy.utils.subprocess.create_job_object_for_cleanup()[source]
+
+ +
+
+koapy.utils.subprocess.job_handle[source]
+
+ +
+
+koapy.utils.subprocess.make_process_die_when_parent_dies(pid)[source]
+
+ +
+
+class koapy.utils.subprocess.Popen(*args, **kwargs)[source]
+

Bases: subprocess.Popen

+
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/autoapi/koapy/utils/threading/index.html b/autoapi/koapy/utils/threading/index.html new file mode 100644 index 00000000..1ccdf827 --- /dev/null +++ b/autoapi/koapy/utils/threading/index.html @@ -0,0 +1,186 @@ + + + + + + + + + koapy.utils.threading — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

koapy.utils.threading

+
+

Module Contents

+
+

Classes

+ ++++ + + + + + +

Singleton

+
+
+class koapy.utils.threading.Singleton[source]
+
+
+classmethod get_instance(cls, *args, **kwargs)[source]
+
+ +
+ +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/contributing.html b/contributing.html new file mode 100644 index 00000000..afa41b98 --- /dev/null +++ b/contributing.html @@ -0,0 +1,299 @@ + + + + + + + + + Contributing — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Contributing

+

Contributions are welcome, and they are greatly appreciated! Every little bit +helps, and credit will always be given.

+

You can contribute in many ways:

+
+

Types of Contributions

+
+

Report Bugs

+

Report bugs at https://github.com/elbakramer/koapy/issues.

+

If you are reporting a bug, please include:

+
    +
  • Your operating system name and version.

  • +
  • Any details about your local setup that might be helpful in troubleshooting.

  • +
  • Detailed steps to reproduce the bug.

  • +
+
+
+

Fix Bugs

+

Look through the GitHub issues for bugs. Anything tagged with “bug” and “help +wanted” is open to whoever wants to implement it.

+
+
+

Implement Features

+

Look through the GitHub issues for features. Anything tagged with “enhancement” +and “help wanted” is open to whoever wants to implement it.

+
+
+

Write Documentation

+

KOAPY could always use more documentation, whether as part of the +official KOAPY docs, in docstrings, or even on the web in blog posts, +articles, and such.

+
+
+

Submit Feedback

+

The best way to send feedback is to file an issue at https://github.com/elbakramer/koapy/issues.

+

If you are proposing a feature:

+
    +
  • Explain in detail how it would work.

  • +
  • Keep the scope as narrow as possible, to make it easier to implement.

  • +
  • Remember that this is a volunteer-driven project, and that contributions +are welcome :)

  • +
+
+
+
+

Get Started!

+

Ready to contribute? Here’s how to set up koapy for local development.

+
    +
  1. Fork the koapy repo on GitHub.

  2. +
  3. Clone your fork locally:

    +
    $ git clone https://github.com/your_name_here/koapy.git
    +
    +
    +
  4. +
  5. Set up your fork for local development:

    +
    $ # Install poetry if you don't have one:
    +$ # https://python-poetry.org/docs/#installation
    +
    +$ # Example below will install poetry using pipx
    +
    +$ # Install ``pipx``
    +$ pip install pipx
    +$ pipx ensurepath
    +
    +$ # Install ``poetry`` using ``pipx``
    +$ pipx install poetry
    +
    +$ # Run ``poetry install`` to install dependencies
    +$ cd koapy/
    +$ poetry install
    +
    +$ # Install ``pre-commit`` hooks
    +$ poetry run pre-commit install
    +
    +
    +

    When you run poetry install, all the dependencies including development tools will be installed under a virtualenv managed by poetry.

    +

    Then you can run those commands using poetry run command args..., like the last command in the example above.

    +
  6. +
  7. Create a branch for local development:

    +
    $ git checkout -b name-of-your-bugfix-or-feature
    +
    +
    +

    Now you can make your changes locally.

    +
  8. +
  9. When you’re done making changes, you can check if your changes pass some checks:

    +
    $ # Code formatters
    +$ poetry run isort .
    +$ poetry run black .
    +
    +$ # Linters and Static analysis tools
    +$ poetry run flake8 koapy tests
    +$ poetry run pylint koapy tests
    +$ poetry run mypy koapy tests
    +
    +$ # Testing
    +$ poetry run pytest --cov
    +
    +
    +

    Or you can just commit/push your changes to make pre-commit hooks trigger those checks automatically. +If you want to skip those hooks temporarily, add –no-verify option for git commit/push.

    +
  10. +
  11. Commit your changes and push your branch to GitHub:

    +
    $ git add .
    +$ git commit -m "Your detailed description of your changes."
    +$ git push origin name-of-your-bugfix-or-feature
    +
    +
    +
  12. +
  13. Submit a pull request through the GitHub website.

  14. +
+
+
+

Pull Request Guidelines

+

Before you submit a pull request, check that it meets these guidelines:

+
    +
  1. The pull request should include tests.

  2. +
  3. If the pull request adds functionality, the docs should be updated. Put +your new functionality into a function with a docstring, and add the +feature to the list in README.rst.

  4. +
  5. The pull request should work for Python 3.8 and 3.9. Check +https://github.com/elbakramer/koapy/actions/workflows/ci.yml +and make sure that the tests pass for all supported Python versions.

  6. +
+
+
+

Tips

+

To run a subset of tests:

+
$ pytest tests.test_koapy
+
+
+
+
+

Deploying

+

A reminder for the maintainers on how to deploy. +Make sure all your changes are committed (including an entry in HISTORY.rst). +Then run:

+
$ poetry run bump2version patch  # possible: major / minor / patch
+$ git push
+$ git push --follow-tags
+
+
+

Travis will then deploy to PyPI if tests pass.

+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index a6b18255..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -static_html_notebooks: - jupyter nbconvert --to html --output-dir=source/_static/html/notebooks/ source/notebooks_ipynb/*.ipynb - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html deleted file mode 100644 index d69b87b6..00000000 --- a/docs/source/_templates/layout.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "!layout.html" %} -{%- block extrahead %} - {%- if google_site_verification %} - - {%- endif %} -{% endblock %} \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index 7ce071f2..00000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,360 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - -from __future__ import annotations - -import os -import sys - -on_rtd = os.environ.get("READTHEDOCS") == "True" - -docs_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -project_dir = os.path.abspath(os.path.join(docs_dir, "..")) -package_dir = os.path.abspath(os.path.join(project_dir, "koapy")) - -# -- Autodoc mocking configuration --- - -from unittest.mock import MagicMock - -autodoc_mock_imports = [ - "PyQt5", - "PySide2", - "sip", - "qtpy", - "pythoncom", - "pywintypes", - "win32com", - "win32com.client", -] - -for module in autodoc_mock_imports: - sys.modules[module] = MagicMock() - -if "qtpy" in autodoc_mock_imports: - - class QWidget: - __module__ = "qtpy.QtWidgets" - - class QObject: - __module__ = "qtpy.QtCore" - - qtpy = MagicMock() - qtpy.QtWidgets.QWidget = QWidget - qtpy.QtWidgets.QApplication = MagicMock() - qtpy.QtWidgets.QSystemTrayIcon = MagicMock() - qtpy.QtWidgets.QMenu = MagicMock() - qtpy.QtWidgets.QStyle = MagicMock() - qtpy.QtCore.QObject = QObject - qtpy.QtCore.QEvent = MagicMock() - qtpy.QtCore.Qt = MagicMock() - qtpy.QtCore.QTimer = MagicMock() - qtpy.QtCore.QUrl = MagicMock() - qtpy.QtCore.Signal = MagicMock() - qtpy.QtCore.SIGNAL = MagicMock() - qtpy.QtAxContainer.QAxWidget = MagicMock() - qtpy.QtGui.QDesktopServices = MagicMock() - qtpy.QtNetwork.QAbstractSocket = MagicMock() - - sys.modules.update( - { - "qtpy": qtpy, - "qtpy.QtWidgets": qtpy.QtWidgets, - "qtpy.QtCore": qtpy.QtCore, - "qtpy.QtAxContainer": qtpy.QtAxContainer, - "qtpy.QtGui": qtpy.QtGui, - "qtpy.QtNetwork": qtpy.QtNetwork, - } - ) - -if "PySide2" in autodoc_mock_imports: - - class QWidget: # pylint: disable=function-redefined - __module__ = "PySide2.QtWidgets" - - class QObject: # pylint: disable=function-redefined - __module__ = "PySide2.QtCore" - - PySide2 = MagicMock() - PySide2.QtWidgets.QWidget = QWidget - PySide2.QtCore.QObject = QObject - PySide2.QtAxContainer.QAxWidget = MagicMock() - PySide2.QtGui.QDesktopServices = MagicMock() - PySide2.QtNetwork = MagicMock() - - sys.modules.update( - { - "PySide2": PySide2, - "PySide2.QtWidgets": PySide2.QtWidgets, - "PySide2.QtCore": PySide2.QtCore, - "PySide2.QtAxContainer": PySide2.QtAxContainer, - "PySide2.QtGui": PySide2.QtGui, - "PySide2.QtNetwork": PySide2.QtNetwork, - } - ) - -if "PyQt5" in autodoc_mock_imports: - - class QWidget: # pylint: disable=function-redefined - __module__ = "PyQt5.QtWidgets" - - class QObject: # pylint: disable=function-redefined - __module__ = "PyQt5.QtCore" - - PyQt5 = MagicMock() - PyQt5.QtWidgets.QWidget = QWidget - PyQt5.QtCore.QObject = QObject - PyQt5.QAxContainer.QAxWidget = MagicMock() - PyQt5.QtGui.QDesktopServices = MagicMock() - PyQt5.QtNetwork = MagicMock() - - sys.modules.update( - { - "PyQt5": PyQt5, - "PyQt5.QtWidgets": PyQt5.QtWidgets, - "PyQt5.QtCore": PyQt5.QtCore, - "PyQt5.QAxContainer": PyQt5.QAxContainer, - "PyQt5.QtGui": PyQt5.QtGui, - "PyQt5.QtNetwork": PyQt5.QtNetwork, - } - ) - -# -- Import main package after mocking --------------------------------------- - -sys.path.insert(0, project_dir) - -import koapy # noqa: E402 - -# -- Autodoc configuration --- - -add_function_parentheses = False - -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), - "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), - "PyQt5": ("https://www.riverbankcomputing.com/static/Docs/PyQt5/", None), -} - -# -- Project information ----------------------------------------------------- - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "KOAPY" -author = koapy.__author__ -copyright = "2021, " + koapy.__author__ # pylint: disable=redefined-builtin - -# The version info for the project you"re documenting, acts as replacement -# for |version| and |release|, also used in various other places throughout -# the built documents. -# -# The short X.Y version. -version = koapy.__version__ -# The full version, including alpha/beta/rc tags. -release = koapy.__version__ - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named "sphinx.ext.*") or your custom -# ones. -extensions = [ - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.autosectionlabel", - "sphinx.ext.githubpages", - "sphinx.ext.ifconfig", - "sphinx.ext.intersphinx", - "sphinx.ext.napoleon", - "sphinx.ext.viewcode", -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns: list[str] = [] - -# -- Warnings related setting --- - -suppress_warnings = ["autosectionlabel.*"] - -if on_rtd: - keep_warnings = False - autodoc_warningiserror = False -else: - keep_warnings = True - autodoc_warningiserror = True - -# -- Autoapi configuration --------------------------------------------------- - -extensions.append("autoapi.extension") - -autoapi_type = "python" -autoapi_file_patterns = [ - "*.pyi", - "*.py", -] -autoapi_dirs = [package_dir] -autoapi_ignore = [ - "**/examples/*.py", -] -autoapi_keep_files = False -autoapi_options = [ - "members", - # "inherited-members", - "undoc-members", - "show-inheritance", - "show-module-summary", - "imported-members", -] - -if "inherited-members" in autoapi_options and "sphinx.ext.viewcode" in extensions: - extensions.remove("sphinx.ext.viewcode") - -# -- Nbsphinx configuration -------------------------------------------------- - -use_nbsphinx = False - -if not on_rtd and use_nbsphinx: - extensions.append("nbsphinx") - -html_sourcelink_suffix = "" - -# -- Missing reference --- - -from docutils import nodes - -missing_reference_uris = { - "PyQt5.QtWidgets.QWidget": "https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtwidgets/qwidget.html?highlight=qwidget", - "PyQt5.QtCore.QObject": "https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtcore/qobject.html?highlight=qobject", - "PySide2.QtWidgets.QWidget": "https://doc.qt.io/qtforpython/PySide2/QtWidgets/QWidget.html", - "PySide2.QtCore.QObject": "https://doc.qt.io/qtforpython/PySide2/QtCore/QObject.html", -} - - -def missing_reference(_app, _env, node, contnode): - target = node["reftarget"] - uri = missing_reference_uris.get(target) - if uri: - newnode = nodes.reference("", "", internal=False, refuri=uri) - newnode.append(contnode) - return newnode - return None - - -# -- Setup event hooks --- - - -def setup(app): - app.connect("missing-reference", missing_reference) - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" -pygments_style = "sphinx" - -# Theme options are theme-specific and customize the look and feel of a -# theme further. For a list of options available for each theme, see the -# documentation. -# -html_theme_options = { - "description": "Kiwoom Open Api Plus Python", # noqa: E501 - "fixed_sidebar": "true", - "github_user": "elbakramer", - "github_repo": "koapy", - "github_banner": "true", - "github_button": "true", - "github_type": "star", - "donate_url": "https://toon.at/donate/637521884081401532", - "font_family": "'Noto Serif KR', Georgia, 'Times New Roman', Times, serif", - "head_font_family": "'Noto Serif KR', Georgia, 'Times New Roman', Times, serif", - "code_font_family": "'D2Coding', 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace", -} - -if not on_rtd: - html_theme_options["analytics_id"] = "UA-179490468-1" - -html_context = { - "google_site_verification": "true", -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# Edit this css file to override some existing styles. -html_css_files = [ - "css/style.css", -] - -# -- Translation related configuration --- - -gettext_uuid = True -gettext_compact = False - -# -- Options for LaTeX output ------------------------------------------ - -latex_elements = { - "papersize": "a4paper", - "pointsize": "10pt", - "preamble": r""" - \usepackage{kotex} - """, - "figure_align": "htbp", -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto, manual, or own class]). -latex_documents = [ - (master_doc, "koapy.tex", "KOAPY Documentation", "Yunseong Hwang", "manual"), -] - - -# -- Options for manual page output ------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "koapy", "KOAPY Documentation", [author], 1)] - - -# -- Options for Texinfo output ---------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - master_doc, - "koapy", - "KOAPY Documentation", - author, - "koapy", - "One line description of project.", - "Miscellaneous", - ), -] diff --git a/docs/source/notebooks_ipynb/.gitignore b/docs/source/notebooks_ipynb/.gitignore deleted file mode 100644 index 5fdf38c9..00000000 --- a/docs/source/notebooks_ipynb/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.sqlite3 -*.conf \ No newline at end of file diff --git a/docs/source/notebooks_ipynb/getting-historical-stock-price-data.ipynb b/docs/source/notebooks_ipynb/getting-historical-stock-price-data.ipynb deleted file mode 100644 index de7811f4..00000000 --- a/docs/source/notebooks_ipynb/getting-historical-stock-price-data.ipynb +++ /dev/null @@ -1,5045 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 과거 주식 가격 데이터 확보를 위해 지금까지 삽질해 본 것들\n", - "\n", - "요즘은 집에서 컴퓨터에 설치된 HTS 를 통해 주식을 거래하는 것을 넘어서 스마트폰으로 언제든지 어디서든 주식 가격을 확인하고 거래하는게 가능한 세상이다.\n", - "또한 각종 증권사들 뿐만 아니라 다른 다양한 곳에서, 예를 들어 트레이딩뷰 같은 곳에서 제공하는 여러 기본 보조지표들을 포함하는 강력한 차트 툴 처럼,\n", - "주식 가격 분석에 활용 가능한 여러 기능들을 탑재한 프로그램들을 제공하고 있어 누구나 쉽게 기본적인 가격 데이터 분석을 시작해 볼 수 있다.\n", - "\n", - "하지만 그렇게 제공되는 기능들로는 만족하지 못하고, 대신 자신이 직접 나름대로의 방법으로 데이터를 분석해보고 싶은 사람들은,\n", - "아마도 가장 첫번째 난관으로 **주식 가격 데이터를 어떻게 확보해야할지** 부터 고민하게 되지 않을까 생각한다.\n", - "그리고 이 문서는 그렇게 나와 비슷하게 이러한 데이터 확보의 난관에 봉착한 사람들에게 내 일련의 삽질 경험을 공유함으로써 약간이나마 도움이 되었으면 하는 마음에서 적어보려고 한다." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "tags": [] - }, - "source": [ - "## 1. 우리에게 친숙한 포털의 금융 주제 페이지\n", - "\n", - "여기저기 찾다보면 비교적 가장 먼저, 그러고 쉽게 먼저 접할 수 있는 데이터 소스중 하나지 않을까 싶다.\n", - "\n", - "* [네이버 금융 > 시세 탭 > 일별 시세](https://finance.naver.com/item/sise.nhn?code=035420)\n", - "* [다음 금융 > 현재가 탭 > 일자별 주가](https://finance.daum.net/quotes/A035420#current/quote)\n", - "\n", - "접근성 측면에서는 좋은 데이터 소스이지만 아쉬운 점들이 몇가지 있다.\n", - "\n", - "* 데이터 다운로드 기능은 따로 제공하지 않고 있다. 따라서 데이터를 다운로드 받기 위해서는 별도의 웹 크롤러를 사용해야 하는 수도 있다.\n", - " * 직접 구현하는 경우 개발이 필요한 번거로움이 있다. 만약에 웹사이트의 구조가 바뀌는 경우.. 일일이 그에 맞춰 크롤러를 수정해주어야 한다.\n", - " * [다른 능력자 분들께서 이미 구현해주신 코드](https://github.com/FinanceData/FinanceDataReader)가 있어서 그냥 가져다가 사용할 수 있으면 한결 다행이다.\n", - " * 사실 엄밀하게 하자면 위의 라이브러리는 HTML 을 파싱하는 방식이 아니라 아예 XML 형태로 결과를 제공하는 내부 API 를 직접 사용하는것으로 보인다.\n", - " * 서비스 제공자가 우리에게 순순히 크롤링을 당해줄 것인지는 또 다른 문제이다. 대량의 데이터를 다운로드 받고자 하는 경우 차단당할 리스크는 더욱 커진다.\n", - "* 제공하는 과거 데이터는 일자별 데이터 뿐이다. 만약에 분봉 이하의 더 작은 타임프레임의 데이터가 필요한 경우 이를 얻을 수 없다.\n", - "* 데이터를 관리하는 주체마다 데이터의 처리방식이나 보관정책이 조금씩 다를 수 있다. 사용 목적에 따라서 이를 먼저 파악하고 알맞는 데이터 소스를 선택해 다운로드 받아야 할 필요가 있지만 딱히 이에 대해 일일이 자세하게 설명하거나 알려주지는 않는다.\n", - " * 제공하는 가격정보가 수정주가인가? 아니면 수정되지 않은 원래의 가격인가? 수정주가라면 수정주가를 산정하는 기준이나 수식은 어떻게 되어있는가?\n", - " * 다음에서 제공하고 있는 NAVER(035420) 의 2003.01.02 종가는 49,800원 이지만 네이버에서 제공하고 있는 NAVER(035420) 의 2003.01.02 종가는 24,900원 이다. 과연 무엇이 더 정확한 혹은 사용목적에 적합한 가격인가?\n", - " * 제공 주체가 가능한 한 가장 오래된 과거의 데이터까지 저장 및 제공하고 있는가?\n", - " * 네이버는 NAVER(035420) 의 주가를 가장 오래된 2002.10.29 일자까지의 정보를 제공하고 있지만 다음에서는 확인 가능한 가장 오래된 날짜가 2003.01.02 이다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위의 내용중에 크롤러를 직접 구현해보는건 생각만 해도 머리가 아파서 따로 시도해보지 않았다.\n", - "\n", - "참고로 위에서 언급된 [다른 능력자 분들께서 이미 구현해주신 코드](https://github.com/FinanceData/FinanceDataReader)는 아래처럼 사용이 가능한 정도로만 확인했다. 또한 해당 라이브러리는 내부적으로 네이버측의 주식 가격정보 API 를 활용하고 있는 것을 확인할 수 있었다." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import FinanceDataReader as fdr" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "code = '035420'" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fdr_data = fdr.DataReader(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
OpenHighLowCloseVolumeChange
Date
2002-10-29231223122312231220549NaN
2002-10-3025872587255825888536380.119377
2002-10-3126262689239824591320880-0.049845
2002-11-012520259922152305750761-0.062627
2002-11-042285230021352191692165-0.049458
.....................
2022-01-10339000339500329000335000828611-0.008876
2022-01-113360003445003345003350008050840.000000
2022-01-1233950035250033950034550010477130.031343
2022-01-133480003520003440003480006772260.007236
2022-01-14341000342500335500342000503520-0.017241
\n", - "

4754 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " Open High Low Close Volume Change\n", - "Date \n", - "2002-10-29 2312 2312 2312 2312 20549 NaN\n", - "2002-10-30 2587 2587 2558 2588 853638 0.119377\n", - "2002-10-31 2626 2689 2398 2459 1320880 -0.049845\n", - "2002-11-01 2520 2599 2215 2305 750761 -0.062627\n", - "2002-11-04 2285 2300 2135 2191 692165 -0.049458\n", - "... ... ... ... ... ... ...\n", - "2022-01-10 339000 339500 329000 335000 828611 -0.008876\n", - "2022-01-11 336000 344500 334500 335000 805084 0.000000\n", - "2022-01-12 339500 352500 339500 345500 1047713 0.031343\n", - "2022-01-13 348000 352000 344000 348000 677226 0.007236\n", - "2022-01-14 341000 342500 335500 342000 503520 -0.017241\n", - "\n", - "[4754 rows x 6 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fdr_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. 아니 외국 사이트들은 주가를 다운로드 받을 수 있던데?\n", - "\n", - "주로 해외 자료를 찾다보면 종종 나오는 웹사이트 기반 데이터 소스들로 아래 정도가 있던 걸로 기억한다.\n", - "\n", - "* [Yahoo Finance > Historical Data](https://finance.yahoo.com/quote/035420.KS/history?p=035420.KS)\n", - "* [Investing.com > General > Historical Data](https://www.investing.com/equities/nhn-corp-historical-data)\n", - "\n", - "앞선 국내 포털의 금융 주제 웹페이지와 구별되는 특징 중 장점이라고 볼 수 있는게 몇가지 있다.\n", - "\n", - "* 데이터를 다운로드 할 수 있는 버튼을 직접적으로 제공한다.\n", - "* 일별 주가 뿐만 아니라 주단위, 월단위 형태의 주가 데이터 또한 얻을 수 있다.\n", - "\n", - "하지만 역시나 한계점은 있다.\n", - "\n", - "* 역시나 제공하는 과거 데이터는 일자별 데이터 뿐이다. 만약에 분봉 이하의 더 작은 타임프레임의 데이터가 필요한 경우 이를 얻을 수 없다.\n", - "* 역시나 데이터를 관리하는 주체마다 데이터의 처리방식이나 보관정책이 조금씩 다를 수 있다. \n", - " * Yahoo Finance 에서는 일반 종가와 수정 종가를 둘 다 제공하고 있지만 역시 해당 값을 어떻게 계산하는지는 알 수 없다.\n", - " * Investing.com 에서 제공하는 NAVER(035420) 의 2011.09.09 기준 종가는 254,340 지만 Yahoo Finance 에서는 50867.44141(Close) 혹은 49895.66797(AdjClose) 이다.\n", - " * 참고로 네이버와 다음에서 확인되는 NAVER(035420) 의 2011.09.09 (일반) 종가는 207,500 이다.\n", - " * Investing.com 의 경우 기간을 최대로 설정하더라도 한번에 가져올 수 있는 데이터의 개수에는 제한이 있어 보인다.\n", - "* 다운로드를 자동화 하는 것은 또 다른 이슈다.\n", - " * 다운로드 링크가 일반적인 하이퍼링크로 구현된 경우 해당 API 주소를 역으로 분석해 직접 활용할 수 있겠다.\n", - " * Yahoo Finance 가 이에 해당되어 보인다.\n", - " * Investing.com 은 다운로드 버튼이 자바스크립트 기반으로 동작한다.\n", - " * 리버스 엔지니어링이 상대적으로 어렵게 된다.\n", - " * 최악의 경우 selenium 과 같은 headless web browser 를 활용한 자동화가 필요할 수 있다.\n", - " * Investing.com 의 경우 데이터를 다운로드 받기 위해서는 로그인이 필요하다. 자동화 하는데 있어서 또 하나의 걸림목이다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "비교적 쉬워보이는 Yahoo Finance 출처에 대한 데이터 다운로더 툴을 간단하게 개발해봤는데 다음과 같았다." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import io\n", - "import requests\n", - "import pandas as pd\n", - "\n", - "class YahooFinanceKrxHistoricalDailyPriceDataDownloader:\n", - "\n", - " def __init__(self):\n", - " self._headers = {\n", - " 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',\n", - " }\n", - "\n", - " def download(self, symbol, start_date=None, end_date=None):\n", - " if start_date is None:\n", - " start_date = pd.Timestamp(1990, 1, 1)\n", - " elif not isinstance(start_date, pd.Timestamp):\n", - " start_date = pd.Timestamp(start_date)\n", - " if end_date is None:\n", - " end_date = pd.Timestamp.now().normalize() + pd.Timedelta(1, unit='day')\n", - " elif not isinstance(end_date, pd.Timestamp):\n", - " end_date = pd.Timestamp(end_date)\n", - "\n", - " url = 'https://query1.finance.yahoo.com/v7/finance/download/%s.KS' % symbol.upper()\n", - " params = {\n", - " 'period1': int(start_date.timestamp()),\n", - " 'period2': int(end_date.timestamp()),\n", - " 'interval': '1d',\n", - " 'events': 'history',\n", - " 'includeAdjustedClose': 'true',\n", - " }\n", - " response = requests.get(url, params=params, headers=self._headers)\n", - " df = pd.read_csv(io.BytesIO(response.content), parse_dates=['Date'], index_col='Date')\n", - "\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "yahoo_downloader = YahooFinanceKrxHistoricalDailyPriceDataDownloader()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "yahoo_data = yahoo_downloader.download(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
OpenHighLowCloseAdj CloseVolume
Date
2002-10-291797.7248541797.7248541797.7248541797.7248541763.381226501745
2002-10-302012.2260742012.2260741989.7545172012.2260741973.78454620892185
2002-10-312042.8691412091.8979491865.1395261912.1254881875.59631332327083
2002-11-011961.1544192022.4404301724.1815191793.6390381759.37353518373668
2002-11-041777.2961431789.5533451660.8525391703.7528081671.20434616939411
.....................
2022-01-10339000.000000339500.000000329000.000000335000.000000335000.000000828611
2022-01-11336000.000000344500.000000334500.000000335000.000000335000.000000805084
2022-01-12339500.000000352500.000000339500.000000345500.000000345500.0000001047713
2022-01-13348000.000000352000.000000344000.000000348000.000000348000.000000677226
2022-01-14341000.000000342500.000000335500.000000342000.000000342000.000000503181
\n", - "

4802 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " Open High Low Close \\\n", - "Date \n", - "2002-10-29 1797.724854 1797.724854 1797.724854 1797.724854 \n", - "2002-10-30 2012.226074 2012.226074 1989.754517 2012.226074 \n", - "2002-10-31 2042.869141 2091.897949 1865.139526 1912.125488 \n", - "2002-11-01 1961.154419 2022.440430 1724.181519 1793.639038 \n", - "2002-11-04 1777.296143 1789.553345 1660.852539 1703.752808 \n", - "... ... ... ... ... \n", - "2022-01-10 339000.000000 339500.000000 329000.000000 335000.000000 \n", - "2022-01-11 336000.000000 344500.000000 334500.000000 335000.000000 \n", - "2022-01-12 339500.000000 352500.000000 339500.000000 345500.000000 \n", - "2022-01-13 348000.000000 352000.000000 344000.000000 348000.000000 \n", - "2022-01-14 341000.000000 342500.000000 335500.000000 342000.000000 \n", - "\n", - " Adj Close Volume \n", - "Date \n", - "2002-10-29 1763.381226 501745 \n", - "2002-10-30 1973.784546 20892185 \n", - "2002-10-31 1875.596313 32327083 \n", - "2002-11-01 1759.373535 18373668 \n", - "2002-11-04 1671.204346 16939411 \n", - "... ... ... \n", - "2022-01-10 335000.000000 828611 \n", - "2022-01-11 335000.000000 805084 \n", - "2022-01-12 345500.000000 1047713 \n", - "2022-01-13 348000.000000 677226 \n", - "2022-01-14 342000.000000 503181 \n", - "\n", - "[4802 rows x 6 columns]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "yahoo_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "좀 더 찾다보니 역시나 이미 다른 능력자들이 구현해놓은게 있었다. 역시나 머리가 나쁘면 혼자 바퀴를 발명하는 삽질을 하게 된다." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "import yfinance as yf" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "stock = yf.Ticker('%s.KS' % code)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "yf_data = stock.history(period='max')" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
OpenHighLowCloseVolumeDividendsStock Splits
Date
2002-10-291763.3808591763.3808591763.3808591763.3808595017450.00.0
2002-10-301973.7843021973.7843021951.7420431973.784302208921850.00.0
2002-10-312003.8419832051.9341411829.5077321875.596069323270830.00.0
2002-11-011923.6885851983.8037901691.2428081759.373413183736680.00.0
2002-11-041743.3427101755.3657511629.1236431671.204346169394110.00.0
........................
2022-01-10339000.000000339500.000000329000.000000335000.0000008286110.00.0
2022-01-11336000.000000344500.000000334500.000000335000.0000008050840.00.0
2022-01-12339500.000000352500.000000339500.000000345500.00000010477130.00.0
2022-01-13348000.000000352000.000000344000.000000348000.0000006772260.00.0
2022-01-14341000.000000342500.000000335500.000000342000.0000005031810.00.0
\n", - "

4802 rows × 7 columns

\n", - "
" - ], - "text/plain": [ - " Open High Low Close \\\n", - "Date \n", - "2002-10-29 1763.380859 1763.380859 1763.380859 1763.380859 \n", - "2002-10-30 1973.784302 1973.784302 1951.742043 1973.784302 \n", - "2002-10-31 2003.841983 2051.934141 1829.507732 1875.596069 \n", - "2002-11-01 1923.688585 1983.803790 1691.242808 1759.373413 \n", - "2002-11-04 1743.342710 1755.365751 1629.123643 1671.204346 \n", - "... ... ... ... ... \n", - "2022-01-10 339000.000000 339500.000000 329000.000000 335000.000000 \n", - "2022-01-11 336000.000000 344500.000000 334500.000000 335000.000000 \n", - "2022-01-12 339500.000000 352500.000000 339500.000000 345500.000000 \n", - "2022-01-13 348000.000000 352000.000000 344000.000000 348000.000000 \n", - "2022-01-14 341000.000000 342500.000000 335500.000000 342000.000000 \n", - "\n", - " Volume Dividends Stock Splits \n", - "Date \n", - "2002-10-29 501745 0.0 0.0 \n", - "2002-10-30 20892185 0.0 0.0 \n", - "2002-10-31 32327083 0.0 0.0 \n", - "2002-11-01 18373668 0.0 0.0 \n", - "2002-11-04 16939411 0.0 0.0 \n", - "... ... ... ... \n", - "2022-01-10 828611 0.0 0.0 \n", - "2022-01-11 805084 0.0 0.0 \n", - "2022-01-12 1047713 0.0 0.0 \n", - "2022-01-13 677226 0.0 0.0 \n", - "2022-01-14 503181 0.0 0.0 \n", - "\n", - "[4802 rows x 7 columns]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "yf_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "값을 앞선 결과와 비교해보니 기본적으로 수정주가의 형태로 가져오는 것으로 보인다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. 일반적인 웹 사이트들은 못써먹겠다. 공식 데이터 관리처에서 데이터를 받아올 수 있을까?\n", - "\n", - "우리나라의 주식 거래 데이터는 당연하게도 [한국거래소(KRX)](http://krx.co.kr/main/main.jsp) 가 관리하고 있다. 이건 약간 TMI 지만 사실 실제 내부적으로 거래소의 전산관련 업무는 [코스콤](https://www.koscom.co.kr/portal/main.do)이라는 회사에서 맡아서 관리하고 있긴 하다.\n", - "어찌 되었든 여기서 어떻게 데이터를 받아올수만 있다면 데이터의 신뢰성과 관련해서는 걱정할 필요가 없어 보인다.\n", - "\n", - "### KRX 데이터 상품\n", - "\n", - "여기저기 찾다보니 거래소에서 데이터를 상품으로 팔고 있다는걸 먼저 알아냈다. 가격이 그리 부담스럽지 않다면 데이터를 구매하는게 가장 바람직하지 않을까?\n", - "\n", - "아래 페이지에서 데이터 구입에 대한 안내를 하고 있다.\n", - "\n", - "* [KRX 데이터 구입 안내](https://data.krx.co.kr/contents/MDC/DATA/datasale/index.cmd?viewNm=MDCDATA001)\n", - "\n", - "판매 데이터의 가격을 확인해봤다. 위의 페이지에 첨부된 문서에서 가장 일반적인 *주식 > 일별매매정보 > 유가/코스닥 > 전체항목* 을 먼저 확인해봤다. 가격은 **1년치 30만원**...\n", - "단순하게 2000년 부터 시작하는 것으로 가정하고 20년 정도를 구매한다 하면 600만원이다.\n", - "만약에 이 데이터를 구매하면 내가 600만원 이상을 벌 수 있을까? 나는 도저히 본전도 못 채울 것 같아서 바로 포기했다.\n", - "\n", - "혹시나 해서 데이터 구입 안내 메뉴 바로 밑의 페이지에서 좀 더 구체적인 견적도 내어봤는데 결과는 아래와 같다.\n", - "\n", - "* 선택형 데이터 > 주식 > 일별 시세정보\n", - "* 대상선택: 유가증권\n", - "* 기간: 1996.01 ~ 2021.02\n", - "* 항목선택: 기본옵션 (OHLCV 포함)\n", - "* 예상가격: 3,775,000원\n", - "\n", - "만약에 해당 가격이 부담되지 않는 사람이 있다면 (그 사람은 더이상 주식투자를 하지 않아도 되지 않나 싶지만) 도전해보고 알려주길 바란다.\n", - "\n", - "### KRX 정보데이터 시스템\n", - "\n", - "좀 더 찾다보니 어느정도 기본적인 통계 정보들은 해당 사이트상에서 확인이 가능하도록 제공중인 것을 알게 되었다.\n", - "\n", - "구체적으로 아래 페이지에서 개별종목의 일별 시세추이를 확인할 수 있다. 무려 다운로드도 가능했다!\n", - "\n", - "* [KRX 정보데이터 시스템 > 통계 > 기본 통계 > 주식 > 종목시세 > 개별종목 시세추이](http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201020103)\n", - "\n", - "관련해서 [다른 능력자 분들께서 이미 구현해놓으신 코드](https://github.com/FinanceData/FinanceDataReader/blob/b28bfb5f802f7ad5ad8012a59c32553225e40040/krx/data.py)를 참고하면서, 추가적으로 약간의 리버스 엔지니어링을 거쳐 아래와 같은 툴을 개발할 수 있었다." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "import requests\n", - "import pandas as pd\n", - "\n", - "class KrxHistoricalDailyPriceDataDownloader:\n", - "\n", - " def __init__(self):\n", - " self._headers = {\n", - " 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',\n", - " }\n", - "\n", - " self._stocks = None\n", - " self._stocks_delisted = None\n", - "\n", - " self._bld = 'dbms/MDC/STAT/standard/MDCSTAT01701'\n", - "\n", - " def get_stocks(self):\n", - " data = {\n", - " 'mktsel': 'ALL',\n", - " 'typeNo': '0',\n", - " 'searchText': '',\n", - " 'bld': 'dbms/comm/finder/finder_stkisu',\n", - " }\n", - " url = 'http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd'\n", - " response = requests.post(url, data, headers=self._headers)\n", - " df = pd.json_normalize(response.json()['block1'])\n", - " df = df.set_index('short_code')\n", - " return df\n", - "\n", - " def get_stocks_delisted(self):\n", - " data = {\n", - " 'mktsel': 'ALL',\n", - " 'searchText': '',\n", - " 'bld': 'dbms/comm/finder/finder_listdelisu',\n", - " }\n", - " url = 'http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd'\n", - " response = requests.post(url, data, headers=self._headers)\n", - " df = pd.json_normalize(response.json()['block1'])\n", - " df = df.set_index('short_code')\n", - " return df\n", - "\n", - " @property\n", - " def stocks(self):\n", - " if self._stocks is None:\n", - " self._stocks = self.get_stocks()\n", - " return self._stocks\n", - "\n", - " @property\n", - " def stocks_delisted(self):\n", - " if self._stocks_delisted is None:\n", - " self._stocks_delisted = self.get_stocks_delisted()\n", - " return self._stocks_delisted\n", - "\n", - " def get_full_code(self, symbol):\n", - " if symbol in self.stocks.index:\n", - " return self.stocks.loc[symbol]['full_code']\n", - " if symbol in self.stocks_delisted.index:\n", - " return self.stocks_delisted.loc[symbol]['full_code']\n", - " raise ValueError('No full_code found for given symbol %s' % symbol)\n", - "\n", - " def download(self, symbol, start_date=None, end_date=None):\n", - " if start_date is None:\n", - " start_date = pd.Timestamp(1980, 1, 1)\n", - " if end_date is None:\n", - " end_date = pd.Timestamp.now().normalize() + pd.Timedelta(1, unit='day')\n", - "\n", - " full_code = self.get_full_code(symbol)\n", - "\n", - " url = 'http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd'\n", - " data = {\n", - " 'bld': self._bld,\n", - " 'isuCd': full_code,\n", - " 'isuCd2': '',\n", - " 'strtDd': start_date.strftime(\"%Y%m%d\"),\n", - " 'endDd': end_date.strftime(\"%Y%m%d\"),\n", - " 'share': '1',\n", - " 'money': '1',\n", - " 'csvxls_isNo': 'false',\n", - " }\n", - " response = requests.post(url, data, headers=self._headers)\n", - " df = pd.json_normalize(response.json()['output'])\n", - "\n", - " if df.shape[0] == 0:\n", - " return None\n", - "\n", - " column_names = {\n", - " 'TRD_DD':'Date',\n", - " 'ISU_CD':'Code',\n", - " 'ISU_NM':'Name',\n", - " 'MKT_NM':'Market',\n", - " 'SECUGRP_NM':'SecuGroup',\n", - " 'TDD_CLSPRC':'Close',\n", - " 'FLUC_TP_CD':'UpDown',\n", - " 'CMPPRVDD_PRC':'Change',\n", - " 'FLUC_RT':'ChangeRate',\n", - " 'TDD_OPNPRC':'Open',\n", - " 'TDD_HGPRC':'High',\n", - " 'TDD_LWPRC':'Low',\n", - " 'ACC_TRDVOL':'Volume',\n", - " 'ACC_TRDVAL':'Amount',\n", - " 'MKTCAP':'MarCap',\n", - " 'CMPPREVDD_PRC': 'Change',\n", - " 'LIST_SHRS': 'Shares',\n", - " }\n", - " df = df.rename(columns=column_names)\n", - "\n", - " df['Date'] = pd.to_datetime(df['Date'])\n", - " df['ChangeRate'] = pd.to_numeric(df['ChangeRate'].str.replace(',', ''))\n", - "\n", - " int_columns = [\n", - " 'Close',\n", - " 'UpDown',\n", - " 'Change',\n", - " 'Open',\n", - " 'High',\n", - " 'Low',\n", - " 'Volume',\n", - " 'Amount',\n", - " 'MarCap',\n", - " 'Shares'\n", - " ]\n", - "\n", - " for col in int_columns:\n", - " if col in df.columns:\n", - " df[col] = pd.to_numeric(df[col].str.replace(',', ''), errors='coerce')\n", - " \n", - " df.set_index('Date', inplace=True)\n", - "\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "krx_downloader = KrxHistoricalDailyPriceDataDownloader()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "krx_data = krx_downloader.download(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CloseUpDownChangeChangeRateOpenHighLowVolumeAmountMarCapShares
Date
2022-01-143420002-6000-1.7234100034250033550050403417110517550056104787070000164049085
2022-01-13348000125000.7234800035200034400067722623632286850657089081580000164049085
2022-01-123455001105003.13339500352500339500104771336405795100056678958867500164049085
2022-01-11335000300.0033600034450033450080508427227111902154956443475000164049085
2022-01-103350002-3000-0.8933900033950032900082861127647871750054956443475000164049085
....................................
2002-11-04417002-2200-5.01435004380040650692165289517468503101249850007437050
2002-11-01439002-2900-6.20480004950042200750761344320260503264864950007437050
2002-10-31468002-2450-4.975000051200456501320880639792496003480539400007437050
2002-10-30492504525011.93492504925048700853638420304034003662747125007437050
2002-10-2944000422000100.00440004400044000205499041560003272302000007437050
\n", - "

4754 rows × 11 columns

\n", - "
" - ], - "text/plain": [ - " Close UpDown Change ChangeRate Open High Low \\\n", - "Date \n", - "2022-01-14 342000 2 -6000 -1.72 341000 342500 335500 \n", - "2022-01-13 348000 1 2500 0.72 348000 352000 344000 \n", - "2022-01-12 345500 1 10500 3.13 339500 352500 339500 \n", - "2022-01-11 335000 3 0 0.00 336000 344500 334500 \n", - "2022-01-10 335000 2 -3000 -0.89 339000 339500 329000 \n", - "... ... ... ... ... ... ... ... \n", - "2002-11-04 41700 2 -2200 -5.01 43500 43800 40650 \n", - "2002-11-01 43900 2 -2900 -6.20 48000 49500 42200 \n", - "2002-10-31 46800 2 -2450 -4.97 50000 51200 45650 \n", - "2002-10-30 49250 4 5250 11.93 49250 49250 48700 \n", - "2002-10-29 44000 4 22000 100.00 44000 44000 44000 \n", - "\n", - " Volume Amount MarCap Shares \n", - "Date \n", - "2022-01-14 504034 171105175500 56104787070000 164049085 \n", - "2022-01-13 677226 236322868506 57089081580000 164049085 \n", - "2022-01-12 1047713 364057951000 56678958867500 164049085 \n", - "2022-01-11 805084 272271119021 54956443475000 164049085 \n", - "2022-01-10 828611 276478717500 54956443475000 164049085 \n", - "... ... ... ... ... \n", - "2002-11-04 692165 28951746850 310124985000 7437050 \n", - "2002-11-01 750761 34432026050 326486495000 7437050 \n", - "2002-10-31 1320880 63979249600 348053940000 7437050 \n", - "2002-10-30 853638 42030403400 366274712500 7437050 \n", - "2002-10-29 20549 904156000 327230200000 7437050 \n", - "\n", - "[4754 rows x 11 columns]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "krx_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "해당 출처의 데이터를 사용하면 아래와 같은 장점이 있다고 생각한다.\n", - "\n", - "* 가장 공식적인 데이터이다.\n", - "* 그렇기 때문에 데이터의 정확도와 관련해서 가장 신뢰할 수 있는 출처이지 않을까 싶다.\n", - "\n", - "다만 아래는 조금은 아쉬운 부분이다.\n", - "\n", - "* 역시나 제공하는 과거 데이터는 일자별 데이터 뿐이다. 만약에 분봉 이하의 더 작은 타임프레임의 데이터가 필요한 경우 별도로 돈을 주고 데이터를 사야 한다.\n", - "* 위에서 제공중인 페이지에서는 수정주가는 따로 제공되지 않는다. 필요하다면 별도로 계산을 해줘야 한다.\n", - "\n", - "필자는 혹시나 매번 각 종목에 대한 전체 일자에 대한 데이터를 받아오는 것이 거래소의 서버에 부담이 되지 않을까 우려해,\n", - "아래처럼 로컬에 데이터를 저장하고 정말 필요한 경우에만 최신 데이터를 요청해 덧붙여 나가는 식으로 추가적으로 구현해 사용 중이다.\n", - "수정주가가 아닌 액면 그대로의 주가 데이터를 다루다 보니 과거의 데이터는 별도 오류로 인한 수정이 필요하지 않는 이상 갱신할 필요가 없어서 가능한 동작이다." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "from sqlalchemy import create_engine, inspect\n", - "from sqlalchemy import Table, MetaData\n", - "\n", - "from exchange_calendars import get_calendar\n", - "from tqdm import tqdm\n", - "\n", - "class KrxHistoricalDailyPriceDataLoader:\n", - "\n", - " def __init__(self, filename):\n", - " self._downloader = KrxHistoricalDailyPriceDataDownloader()\n", - " self._engine = create_engine('sqlite:///' + filename)\n", - " self._inspector = inspect(self._engine)\n", - " self._calendar = get_calendar('XKRX')\n", - "\n", - " def load_naive(self, symbol):\n", - " data = pd.read_sql_table(symbol, self._engine, index_col='Date', parse_dates=['Date'])\n", - " return data\n", - "\n", - " def load_if_exists(self, symbol):\n", - " if self._inspector.has_table(symbol):\n", - " data = self.load_naive(symbol)\n", - " if data.shape[0] > 0:\n", - " return data\n", - "\n", - " def load_or_download(self, symbol, start_date=None, end_date=None, save=True):\n", - " if end_date is None:\n", - " now = pd.Timestamp.now(self._calendar.tz).floor(\"T\")\n", - " end_date = self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize()\n", - " if self._inspector.has_table(symbol):\n", - " data = self.load_naive(symbol)\n", - " data = data.sort_index()\n", - " if data.shape[0] > 0:\n", - " start_date = data.index.max().tz_localize(self._calendar.tz) + self._calendar.day\n", - " if start_date < end_date:\n", - " recent_data = self._downloader.download(symbol, start_date, end_date)\n", - " if recent_data is not None and recent_data.shape[0] > 0:\n", - " data = data.combine_first(recent_data)[data.columns]\n", - " data = data.convert_dtypes(convert_floating=False)\n", - " data = data.sort_index()\n", - " if save:\n", - " data.to_sql(symbol, self._engine, if_exists='replace')\n", - " return data\n", - " else:\n", - " Table(symbol, MetaData()).drop(self._engine)\n", - " if not self._inspector.has_table(symbol):\n", - " if start_date is None:\n", - " start_date = pd.Timestamp(1980, 1, 1)\n", - " data = self._downloader.download(symbol, start_date, end_date)\n", - " if data is not None and data.shape[0] > 0:\n", - " data = data.convert_dtypes(convert_floating=False)\n", - " data = data.sort_index()\n", - " if save:\n", - " data.to_sql(symbol, self._engine, if_exists='replace')\n", - " return data\n", - "\n", - " def load(self, symbol):\n", - " return self.load_or_download(symbol)\n", - "\n", - " def load_all(self, include_delisted=False, progress_bar=False):\n", - " symbols_with_delisted = {}\n", - " result = {}\n", - "\n", - " symbols = self._downloader.stocks.index.tolist()\n", - " for symbol in symbols:\n", - " symbols_with_delisted.setdefault(symbol, False)\n", - "\n", - " if include_delisted:\n", - " symbols = self._downloader.stocks_delisted.index.tolist()\n", - " for symbol in symbols:\n", - " symbols_with_delisted.setdefault(symbol, True)\n", - "\n", - " now = pd.Timestamp.now(self._calendar.tz)\n", - " end_date = self._calendar.previous_close(now).normalize()\n", - "\n", - " disable = not progress_bar\n", - "\n", - " for symbol, _delisted in tqdm(symbols_with_delisted.items(), disable=disable):\n", - " data = self.load_or_download(symbol, end_date=end_date)\n", - " if data is not None:\n", - " result[symbol] = data\n", - "\n", - " return result" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "krx_loader = KrxHistoricalDailyPriceDataLoader('data.sqlite3')" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "krx_data = krx_loader.load(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CloseUpDownChangeChangeRateOpenHighLowVolumeAmountMarCapShares
Date
2002-10-2944000422000100.00440004400044000205499041560003272302000007437050
2002-10-30492504525011.93492504925048700853638420304034003662747125007437050
2002-10-31468002-2450-4.975000051200456501320880639792496003480539400007437050
2002-11-01439002-2900-6.20480004950042200750761344320260503264864950007437050
2002-11-04417002-2200-5.01435004380040650692165289517468503101249850007437050
....................................
2022-01-103350002-3000-0.8933900033950032900082861127647871750054956443475000164049085
2022-01-11335000300.0033600034450033450080508427227111902154956443475000164049085
2022-01-123455001105003.13339500352500339500104513836316514050056678958867500164049085
2022-01-13348000125000.7234800035200034400067722623632286850657089081580000164049085
2022-01-143420002-6000-1.7234100034250033550050403417110517550056104787070000164049085
\n", - "

4754 rows × 11 columns

\n", - "
" - ], - "text/plain": [ - " Close UpDown Change ChangeRate Open High Low \\\n", - "Date \n", - "2002-10-29 44000 4 22000 100.00 44000 44000 44000 \n", - "2002-10-30 49250 4 5250 11.93 49250 49250 48700 \n", - "2002-10-31 46800 2 -2450 -4.97 50000 51200 45650 \n", - "2002-11-01 43900 2 -2900 -6.20 48000 49500 42200 \n", - "2002-11-04 41700 2 -2200 -5.01 43500 43800 40650 \n", - "... ... ... ... ... ... ... ... \n", - "2022-01-10 335000 2 -3000 -0.89 339000 339500 329000 \n", - "2022-01-11 335000 3 0 0.00 336000 344500 334500 \n", - "2022-01-12 345500 1 10500 3.13 339500 352500 339500 \n", - "2022-01-13 348000 1 2500 0.72 348000 352000 344000 \n", - "2022-01-14 342000 2 -6000 -1.72 341000 342500 335500 \n", - "\n", - " Volume Amount MarCap Shares \n", - "Date \n", - "2002-10-29 20549 904156000 327230200000 7437050 \n", - "2002-10-30 853638 42030403400 366274712500 7437050 \n", - "2002-10-31 1320880 63979249600 348053940000 7437050 \n", - "2002-11-01 750761 34432026050 326486495000 7437050 \n", - "2002-11-04 692165 28951746850 310124985000 7437050 \n", - "... ... ... ... ... \n", - "2022-01-10 828611 276478717500 54956443475000 164049085 \n", - "2022-01-11 805084 272271119021 54956443475000 164049085 \n", - "2022-01-12 1045138 363165140500 56678958867500 164049085 \n", - "2022-01-13 677226 236322868506 57089081580000 164049085 \n", - "2022-01-14 504034 171105175500 56104787070000 164049085 \n", - "\n", - "[4754 rows x 11 columns]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "krx_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. 사실 당연하게도 HTS 에서 데이터를 얻을 수 있다.\n", - "\n", - "키움증권의 영웅문 HTS 기준으로 아래처럼 하면 단일 종목의 과거 가격데이터를 엑셀파일로 저장할 수 있다.\n", - "\n", - "1. 키움증권 영웅문 HTS 실행 및 접속\n", - "2. 키움종합차트 창 생성\n", - "3. 원하는 종목코드를 입력해 차트 불러오기\n", - "4. 필요하다면 우측상단의 톱니버튼을 클릭해 수정주가 적용여부 설정 (기본값은 수정주가 적용)\n", - "5. 우측상단의 연속조회 버튼을 최대한 많이 클릭해 최대한 많은 과거 데이터를 불러오기\n", - "6. 차트화면 우클릭 후 데이타표 저장 기능 클릭\n", - "7. 저장할 항목 설정 창에서 원하는 항목 체크 후 확인 버튼 클릭\n", - "8. 최종적으로 엑셀파일을 원하는 경로에 원하는 이름으로 저장" - ] - }, - { - "attachments": { - "5aedfddd-56b6-4501-99cb-e878b3b24020.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABJcAAALRCAYAAADm2EKjAAAgAElEQVR4Aey9XcwtWXUdeh78kui+3MfIV9cveYif730IV7oSlnhD0X2IdGPpvsQhcnQekjgEZCIcjDiJFWPFJBD8EydpsAxBcoON1aQJGBs1WFjmR+646ab5gMamZTc4ho75icG06mrsPuMwzjhzrlpVu2rv2rtmSfXNNeccc65Vc83au/Y4+/vOrZe+7OVDnVWD6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oE5PXBrTlDFVLNVD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD6AHilyqb27VN9eqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgdm90CRS9U8s5unGOpiqKsHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgceIJfu3Lkz1Fk1qB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB7IekBJxZBcesn/++ahzqpB9UD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9YD3AAinIpeKPCvysHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqB6YFYPFLlUjTOrcZylLL2Y6+qB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqBffZAkUtFLhW5VD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9MLsHilyq5pndPMVI75ORrn2vfa8eqB6oHqgeqB6oHqgeqB6oHqgeqB6oHtAemE0uPfz+x4feA1idtMbVhNUD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD1QPX2gOvufPWXfEgs8glEks/8hOPDD0nSKgimOpF41pfNOq6qrerB6oHqgeqB6oHqgeqB6oHqgeqB7bcA+/4jU8OU84p19KbdyxnT54lcmCesTzw+3p6YhRT5NLLXn7ffx8H9kkLhDGOHlJJMYjxPNQPCQM/7R67tJ3raEmdU8eM8TWqXfEc06+SvkwqFmM9Ip/bWjHI5XjNH40dv4Tu61Bd16BzRXa1aQ7GZTbGEQepR49dMTrWPBi7T3WMx44xvPp9PuZXjI4jPGOidWksx8RRp6S9NQexLZnliexq49hzwx7ZInyG9XjoPCJfZCM+k1EM53EfcrjN9TEM1+Fx0KNY4iNfFpPlZi710+b5MztjHc+1MI442lXPbLRHuT2eus+nsTrW3Iyh1FwcUzqGdkgcqtMWxdDmMbR7nkgnNpKc2+N8PvVHvii32jSec0Z56MvwGqP5OY7i1EYcpftUxxiH22jPfI7nXC6Ja+WJfJktsnOtnIsSWB60UdIOSRuk67RFdo3j+JDAfmgOuoh3X2RXWwvvOOqcE5K2LI9iOWaM67RHklhKYqirhM8P4tWnNrUjVn2aS+2tsefoyd/KF/myORSra9cxMVEO9UUx9FMSo3o0Vls0L/O4b6qd87icmifDM29rnZGPcZSOUXvmI8Yl8NHhOOhjh8YAqzrjaYv8xETzME4lcWrLxk6UjOlZnsg+lov+KFZtxLWk4qMxY+kb04lzOTdO8xS5dCZySTcBY7/ZqFMST52y1+446lOkzqlj5ohsPT5geBA/VbbmjnJF+MgWxS5p0zmzMeajj5JroE7p9ql6liezM79Lx8OvNh17bKQ73vWe/FEM54p8kW0q3nNEuts4h0rHUKckljql2zOd9kx6PuKm2hnXkllOj4lwka0nTjFZDthxtLCR320az7FjqFM6LrM7jvqY9HzET7UzjlLjOaYERseRTtsBePcHc1N6DrW7L9Mzu+biuFd6TsRltoMj+dE7Xyt/lIPTqc/XR51SsTp2v+vAqk3HrTz0ZXj6W/IwsfzIsNEcvTbk5KH5PV51HTOese4bs9NP2RtPHGUU7z5g3OY681C6nzql4zK746hnMsvjdsa7XXUdj+Ed6zrjVQKDw21TdMVmY58DuMjm8YrRseN6dI3nmDJbj/o5h9uoUzousxPnMsNPtTNvFkc/pGJ0nGF67IrhOMsNf+SLbMzlMsKqTceMjWwtXwvPOEqQJRyPySlY5OrB92CYC9joHFu3xhPLPJlOu0qPoS+z0+/yVOQS1zUmfX1L67N+LQ5NrN9K4hh2HNRVwp4tPvK5jTql53I7dUrix3TieqTm0jFjI9tUX5QDtuzI8md42BFDyfjMpv41xrqObKxrU0yPnWvO4tyf4TI74106Hn616dhjI93xrvfkR0zr8HmBdRv1yNdjcwx0HMybScdQp2QcdUq3t3TERAdicDBW5VS7xkZj5qOMMLDRT0mc67RT0k9Ju8opvhYWOXlo/mjseahTeozbe3RgooPr9Dnm2D0H5qONY18D/dl8jOvxa64Ir7nUn9mZz/20t2QU02tj3ghPXyQjfGRjrPtcz3C0U3qc68D5wViVURxjFTdlrDl17DkiX6+NuRzfowODgzkgXacvs9NPmeHcTp0yincfMJGNsZF0PHVKxlCndHum0+4yy+N2xrlddR1n+DE7/Zn0OabqWV61e074IpvGOCbCH5I0fmg+jefYQxXv89PHWOqUvfYMl+UhntJxmd1xmQ67H8Sq9Hnoy+z0q2xhIx9srWMsN2KJ0TFtkNmhGI6zHPSrBPGgems8BYs8PfgeDHMBG52tNWc+5sn8kT2LyexRDtgukVzCNWbX0/IhZhFyyW8AJZU4bjV+5HMbdUq/YLdTpyR+TCeuR2ouHWss7NGhGI6Jo07ZsgODg1hKxmQ+4igznObxMWOXlFwHJXO3dPchxm1jOuehJJ6y106cS88Dv9p07LGuR9gx25h/7hyM683vONU5pmTuHskYSsa4HtkzTIRt2Vq+sTkYq9JjXM+witOx4jF2n+vEZ/YpORTbysc5XTKG0v2uK07HjoMe+SMbYyNfZCNepeI4pozWoj7mUZuOIz9tlI7P9Mye5aG9JT0nsL025o3w9LnMsJk9Wk+GzexRjh7bEvn8+iMd8/iR4aJ1ayzjYOPYZcsX5fd46lmezM44ygzndtV1zDyQkT2yaYyPHU+dknjXM3uGI57ScdQpiaN0u+o6zvBjdvoz6XNM1bO8avec8EU2jXHMGP6QsPM+YS5Kn4vrUH/LlsUzRmWUs+UnnpJY1yN7hBmzRf4od8tGn8tT59b5dOzr6tWn5BgjBnTOHiwwxFFqDh/3YBDDvJH0nD068/RgW5g5eS6RXEINcK1ei8jmmEXIJSWQ0ODUVbYaP/K5jTqkHrwg2DiGpE5J35hOnMtDwuAHcZ6X9mNkK6f7xnRdh2Ph67VpnjXGh4XYXkbr8/Ueq+u1aC4d6zoyu+bxMWL0UD/sris2GzPG42FXm45bMWO+Q9LgB+NU9sypGI4pNVc2BhaH+u+aHrATE+Hpi6Tix3IjXvHMF9noc8k53A49ytOyZb7Izvzuc13X5T7oekRY+NU+Nla85lY7c9BPHTLCZX7Gt2IiX2TTOXTMOWjTWB3D7zptB8fdH8xDGcVkPsdSp+yNI64lPSewme3gSH7oHAnkAbPHqK5jBLquyehTWxRDnMo5MYj3/JlN5+K4NWcrj86ZjXUOjl1qbMvn66SOGB4eT19kdxtzqIzi4ddY16MY2jy35vGx56VOSbzrnIt+yghHn0rHUYf0A3E4snj3Ea95GKu2KI44lxFWc/XgHeN6NofjXNc4HRMXrTOyOV71aDxmi+ZQG8bMoTKzKwZjPejz2EiPbIxXqfl7Y7guzZPZHKO6z01dMRzTl0niILODGPg5buE9j8eo3hr3kAOM78ECQxwl4yPZg0Ec80YyyjtmY54xXMs/N8cpyaXW+uHDNYxh1K94HSvGxxdJLulF8KakpI86pdsznfYx2ZMXmLGD84zh6Fc8x5A4WvqYj/k1j441fspY83LciueclMSO6cAp5qDID+ahVCxtnqOle7zrmtPHETay9cQpBjn0cJ/qGI8djp+qI38U4/NyLcRmcfRHkjGUxLgOu9tcZ6xiHeN6FDNmU//ccWsdyDnm75m3lcN9ma52HY/N79gxnfkUp2P6KemjdDt1lY6FL7JpTGussTpm3kNy+8F8jmcM/S4dn+mZnfncT3smiackDjoP2lzC77Zj9FY+92V6Zse63Nez1lZM5ItsPfP0YKLctFFqnshGf+bL7IiLfJEtw3Jula34w4R3f2gMxx7rOnBuc525KN2vOsZ6MIYSPo4pIxt9KjWvxui4Bw9MFOM26pTM7TrtLh03Vfd8rjMfJf2u007pfug8iHEJv9tauuJ1zJgeGzGUWaz7iXPpOOqUxLse2TMMsZFsxUS+yBblXcLWmivyqU3HupbIHtkQk9k1H8ckSFzSr7KHTFCMjjWPjnsxwLVOzdkzZq4ebIQ5Jv6SySXUYuq1F7k08QWfDec3suvEqezBKH5sjHw8xrD0A48xpdupE8P8kVTsUmOui5J5x3THOZ5+ysjfYyOGspWPPpceC39k64lzTKavnT+ad8qcitVxlDeyMYaSmDEdOMfQ5vYDMLl/OB9jVc9sjtmq7nXQdbov09WuY83l4wjnNteZQ+06Vr/boeMAhpJ4lZEvsmnMWuNo3sjG+d2X6Zk9y0N7JpmPkrhIh23sYPwcidxZnPvGdOZRnI7pP0ZG+SJbNgewrUPjgFPdx5E/sjEu8kU24McO5lSZ5VIMc7utZXeszqNj4tzmOnGU7nf9WBzjXfbOwzjF6xh+1yMbMZRRXtoiORY35o9yqo3xlPS5Tjul+yMdtrGD+eZI5PY4t1GnJF51HdOfScdSp2Sc65E9wxA7VUb5ItvUvBEeeXsOxgLLMaXadKz+1hzEUUY56HNJosCl46ADE9nVphgdK0bHYxj4e0/NOzZmzjFc5j8mvsilI/63ON4I+utwHLcaP/K5jTolN586Za/dcdR7pM+FmMx2cCQ/orkSaHhzR3MyZ+ZTezZmjnPIbE1qx7qoU3Kt1Clpd+l+14l3O3XKDEd7JD0WmMx2cCQ/otyZLcrv2BYmWcIDZs3ZykccMQ8kCt6MGQPJONqoU7o906NcxLakz6PYyBfZNIZj4HoO4iHHjilY5vIY1XUMfI/OvCo1zseel363U6eMcO4jpiVbMZEvsmX5gW0dWVxkRx63RzZi3JfpmT3LQ3skW7ncF8WP2ZCjdXg8sG6j7r4xPYrzGMXAlx3EuQS+x+aYHj3K3YqL8JGNOdznOnFjMovL7J4vw/XaFadjzuM214mjdL/rx+IY77J3HsY5XnUdj+Ed6zrjXTpuqu75VG/lcl8rDr4WXmNb40OSxg+PjeZ0G3VK5qBOSfuYdDx1SsZTp3Q7dPcp5uBMfhDnMsoX2TwOeu8RxfbYonWoTcdL5BvLAZLEMZENmMyu8YrBuOfUeB/3xBPjsS19Tkwr3xTfJZNLqBuvVce0RbK+uRQ8uEWFoi17EYjska2VZw4eMdnBuSiB45iSNkrazyV1HdkYa6OPkuulTkm7S/e7TrzbqVNmONoj6bHARLYolrYIH9mI75E98REmsmG+yO421+fGMQ8lr3dMz+Zr2Zk7kz7nMblOERutV6+t5XffmJ5dT09cFMs4Sq5bdR3TH+VSX2sc5YtsrRyZL8oT2bJ42Ft492V6Zue87qc9ko5VXceMjWz0RbKFj3yRjXndl+mZHXncx9wt2YqJfJEtyw9s6/A4YN3W0lt497mueeFrHYrlGHiOWzLD9doVp2PO6ba5+tS4bH7aXXp++nvtitNxlocYyjEc/ZRT4xzPPJF0rOo61tg5dsT4oTl7xoh3XI+NGErmoE5Ju0v3Z/pUO+bxGJ870lsxkS+yRXlpi/CRTfHw+0E/JfwcU6pNx+r3vKoTRxnloM9lRBBENsRlds3Zg1H82Bj5es+xXOpnTrVNGR8TP0YuMfeYHFsv4pfAMEeUL7IRT7kIuaQNr2N+awmy1fiZT3NxwZB6HGNnLs2RjTlny+8+xLiNeuSLbEvhW7kxh/sPho4fXN9SMloHc+tyaIPUg3bPQzul+zUHx4p1G3x6EJtJxfqYubLYyI4cbo9sjqHua8h04imjOSIb8C37wRlcQxYX5WIO92X2LHdm97zAjZ1ZTGYfy5etrSeuN3ZsbS1/5IONR7RO+NzuNsarZExk47XSRywl7BxTRjb6MpnFZPYsT2aP8kS2LB72Fj7yHQLu/tC8mX1sDs+hOsdcByXtkJFN/T5u4SNfZGPOyAcbD+Ig9VA7fW5r6cgV+afap+SIsLBlc87Be65DcvvBvI6lvSV7Y2zKg4q8rXiN0TVkMRk+myfDZ/YsT8uu627hdE6OIzx8zKlj2hijOeijLYqLbMzFeMo5eRhLOTaf+zkn4106Hv7IxriWjxiVET6ycV74cHiOu+Z7duoqPUb1qflbePo8f0v3ayJ2qp1xLqM8kQ1xmT3yHcDBD84f5YpsxEdyCj4iByIb5snsuoYxzJhfc2XjY3MgXs9snpad8S1M5rtEcqlV85YPNViEXFISKRu3Gr/lyzZqKftSc0d5YGsd0TVk+ClY5ohiMhtiMl/Zx0mFY2s0tf4RnvueyWPXiPhs3ih3hI1wY7al8rTmieaArXVE+YCfYo+wbstyOi7Se2LHMGP+aN4ptrXzYy3RHAdj40d0DVGeLH8UP2aL8jeWeHB5ziiHY47Vl5ojynO4qMYPX3sDenBFeLctrWPiKTkz/FR7NOehCI0fHtOAHlwR3m1z9KnzYg4cc+Y6JmbqnFPxc9Z2ijl8XeeY09fg+lJrmponw8MeHb7uMR05HBPZHHOMvnZ+rG3qHBl+qj2rS5QnsjEevuigv1cih2OjvGqL8G7LdJIkvTLLQ3tPHmLnyjEyY27eU8WNkUtLraNnL05Ry82QS9HNtVSxszy8UTN/2dcnVarG11vjS7u/jn0NyuIvrQ5+T176+nk92f7QPyaz+K3VZ+31rJ1/bB+O9Z9q/ZjnmLVm8adaf+/az7Wevc2b7UfV4cVnqHPVIduXte3Xcr24jmNqlcVfS316a3Pt13sKQqS31nNwpyKX5qxtjZhZ5NLD73/80MfZt5TcDjBi1riAynm95MSe9vbP/re/PtQ5vwZ76pW61nrNqx6oHqgeqB6oHqgeqB6oHthDD1w6ubSHPdJrnEUuIQEJJrKlLVnEUr34adPV+MF+KGJpPrGE2lVPPdhTVZOqSfVA9UD1QPVA9UD1QPVA9UD1QPXAqXpgNrl0qgXWPHUz7KEHilwqcmkPfV7XWK/n1QPVA9UD1QNr98ClPVOtXY/KX/dc9UD1wKl6oMiljv8B6lSbUfPs98a/tAehra237p393ju197X31QPVA9UD1QPaA1t7Rhlbj669xtXL1QPVA5fcA0UuFblUv1K0gR4Ye/Aof/ubTZf8Ilxrr4eI6oHqgeqB6oHqgeV64NKemWrvl9v7qmXVsnrgvD1Q5NIGiIW6Cc57E2yh/tGD0BbWtcU1VK3qftliX9aaqi+rB6oHqge20QPRc8KWbdU32+ib2ofah+qB43ugi1x629veNvB8/PHHhzqrBnN64Lnnnhtw3r59+yAxnpPnGmOih55rvM4lrqlqVa8/S/RR5ag+qh6oHqgeuM4eiJ4TtmyrPrzOPqx9rX3dSw+QJ4IscqnIspMRPEUu5S+y0UPPXl6Qpl5n1Srvo6m1LHzVsnqgeqB6oHrg2npgy88JW17btfVBXU+9tlUPnKYHilwqQulkhJLe1EUu5Td4PWzktdEewrhq1V8rr13pVbvqgeqB6oHqgWvvgS0/J2x5bdfeF3V99dpXPbBODxS5VORSkUsb64F62Oh/sata9deq3kSrVtUD1QPVA9UDe+uBLT8nbHlte+uTut56baweWKYHilzaGLGwl8auby7lN3A9bOS18fujatVfK69d6VW76oHqgeqB6oFr74EtPydseW3X3hd1ffXaVz2wTg8sRi79q3/1r4Y6z1MD3BxL136tnLyRx8ilS7ieqWvsrWn0sJHN1Zszi790+5Razb3Wc9T4HHPOrc/W46qW896X9lS3PV3r1u/Xa14f+kwfutcYH1O/c94HmHutM3pOaM11TA2nxkZrm5pjC/hz9s4Wrn+NNbR6tHzrvV5UbY+vrb63HfUHvXFj1TG/AnPrhzi+qM+f/f7INXPypu0hl+5f1XxtyetZYp++/OUvD60zetiI8Ete1/zqrhfZU+uoVj1xvatessa961pyzt7rvFac1vL/ufORYYkTOaP7cY5ty7n4vjLnuqKYS7jW559/fljixLUukQc5Kte0PdlyvXBP4aF7qd6I8sy9fsTxnv/uC8NwypNz8/lwaRk9J7TmwHqWOsZyRWvL5h7LlcVF9qVzsXeiufZiW6OmrT4t3/EkSNVwnRouTi6d8g3pWubCCy9flKKHhcz2hS984RCnL+oZtte+dk7eyL3kUu+6M9zNzc0DNZrbN0vtU/TBS23Rw4b6OUbP6N7Pva4txvXWOqrVnHsp6p8l7wXmwnVFc9FGnO7rW3/l/x6OOTHnXg+9R5YglpADOXkPHiu3nIs9eOw1Mv4SrpX34bES13psDsZXriKX2As9cm6/II73/KmfCTg35l/jjJ4TWvNgPTh66t3C8PmzlStaW5STzwatXFFcZFsjF3vnULid/liqb7g/rR4t3zqvFVXXZepa5NKJ/4UmetPG6/CcFyV9AZoT33rT0TeKCDfFpuvkjVvkUv7tpehhgx/QVGLPdZ+i3rpUW+89EdVqi/cC7wFcV+veIU739RhiCbF7PvQeKXIpf83R1xWMtW7um6sj59xYj1s6F++31r05xYf1TcG3sJWryKVWf7hvbr8gjvfBqZ8bODfmX+OMnhNa82A9/l79t//23w7v6V/8xV8M7diXNcklrGfKqX3C5wy/RsX0jpmLvbP3542la9rq0/Kt83pRdT2+rkUu7YBc+vjHPz489thjh3PsDSN6oxiLGfNrTt60c8ilOW+kfHPHvHxgmPvghDcN5hi7ZvXr9SPePyi5Hj0IOQY6ci1xXXPrsWZcb62jWrX26Itf/OLw5JNPHk7do2js+3bMQwNzjeUgTvc1I5eQy32ZDXYct27dujs6TkceP5lf7fdNdgZF75Eil4pcGnsdjV4H5tjQd3PiopjKVeRS1BeZbW6/6Gvlmu/tUW7OzefDpWX0nNCaA+vBoTVemlxivmht0bx8NuC6EP+BD3zgcGL8p3/6p+FJHOdDbs+l88H3lre8Zfin//SfHp6Tnn322eG1r33t8OY3v3n4/Oc/f19NNJc+s5zhrX4TU0Z9o7XtHXN/Wj1avuMJkKrhejVcjVx6wxveMOjJNxTYMKakPbOp38dRfmKy/BrjY8ZCuo86MdA5Vul26pSK5RivinNelPQFKIp/4oknDm8Kf+fv/J2B59/9u393+K//9b8+8AbBF72xnMRNkZqTN/NWyCX9IByNuUeQS+2Tf8DxeaOHDY/JyKX/4xeHAacetGV2xXKsMYxTG3GQLfsnfvRWeJ9oXaMx8kY97X0X1SqLe+Mb3zj8g3/wD+6d//gf/+Phk5/85NH3wite8YoBp69Ndd4DuC61+5g43Ce8DieQqCMXx5SZDXYc6DU95uoex5xud524U0nUkLVcm1zCtbbO7B6O7LBpLsXArjrHuFaOKTPsmF/rRqzKVt7MF61Pc2KMWJ7uUz3KxTiXjIOdY5V6rX4/Rvo//If/sHkPIwY5o1i1IQ9Ptft4LBdzqPQc1Fu5EE8cZStnliuLyeyY61JyTamRXy+uEa9FeOhmfdeQWS3H5uL6IKP35MyG+8p9eg+qL7Nzbj4fUv7Nv/k3732TCWOe9EPSpli3R88JmsPHWA8O1AykjJ+w4xtLfnqN+Y+bzEU/iR7IaG2Og85nA+ZC7BRyCVjO67k4H+SXvvSl4Wd/9mcHfFZ461vfOvyn//Sfhr/39/7e4TPR008//UDvMhdqyLodinf3h+75MXbEIlfrUP/UeTWv5snmjfLz+llP1JvnJz7xiXtj2FxnDKTW1Huz9PUIkartcrVdlVzim4oSKxxTEgMZ2dQ/ZRzlimzM2fJFmAzvduqUzKUSL17+oqQvNNlYX4A8Hv/CcPv27eGVr3zlvW8sgWz61//6Xx+IJnyTKcrbyhnh8aaDM/LRpjl5826FXNJ9wBhvGG6jvtQ+6QcbH2P+6GHDcdCx56gn9x7rzIigKXYlixiHa6ddx/SrVNwWyKVvfvObwz/7Z/9s+PEf//H7vrH0H//jfzwQTfgmE3tVpfYta6x+jEksXRK5pA9OOsa+9uqOQywOt7t+F3YyofdIRC75QhQDn+ocI2d0P7oN1+4217NcHqu6jjVflCvCwqan5uBY60abyigv/ZkvWh9jpsooVzYvc2d+vVa/v10nYeB215HTbao7SeG6Yqfm0lgfZ7mi6/I1uR7lcgx1Sq7H9UvIhTX7ujM9suMa8X59TeQS7imcfEaCzPTMjhjWhs+HlCSMKOfao2cq5ook1oMD/UpyQCXsTixFvx4XkUvIw/sAMlob51Ucn0d0XUuSSyCO8Cz0m7/5m8PrXve6A7kEgonnj/3Yjw3/5b/8l+GZZ545EFBcG9eFOrJuh+I1ngfQC3pQp6RPdYxVJ0Yl/ZT0Uad0O3VKxWGsOjCZzutnbbRnxsaMgdSaRv1ZtuVIkKrlOrW8SHIJRE128k0uInMiWwtPH6XPSbtKn0NjFKdjvFj5i5K+0GRjfQHy+P/8n//z4U0h+horvuL6L/7Fv7jvDY5ztHISo/LU5BJf/FX+xm/8hqr3/nUG6+Sbu77xae11jDcM6JTqwxiH11lrkY29pvywE0nMHT1sRFisxa8rI3mm2EkOUbK4qnMMiUMlfbBvgVzCN/XwLSWQTL5H+DYTvgLudui+b7gexSmxdGpyCWvBt5Uop3xzSR+MonFkO0wkD1WKoQ/S7a4r9hRjvUdIDlFifo4p1aZj+iGRM7of1Ybrhk6pPh23ciGWp8ZkOaNcGZb5Mr/WjViVXFcmFctxtD76sr1vdNUAACAASURBVDyt9TGWMsuhfo5V6rXq/Z2NnTiIcMgZ2WnzHK4TBzk1l8b6uJXL1zCmR7mymMzO9Z06F+eduq4xPP2UOg+uEe/X10QuRc9LuA/12Yk6JX2qszb6QU8JJR1nGNiJoyQ2eqaiL5JYDw7sX0QKwD6HXHJiCXmitUU4Po/oupYkl/7tv/23w7/8l//y8I9wP/qjPzq8+tWvHt70pjcdvsWEf5j7+3//7x9+E+Lf/bt/N+Af5tjbXBfqyLoditd4HsDe60Gdkr4xnThIxepYfZk9y0P7WBz9vH7WJuqdzMYYSK1p1J9lW4cQqbouV9fNkUtKxviYb0qUJHIoaYfUWNrVFo2Ji6TP4TrnVKnjCM958ALmL0okbSLJFyF9AfJ4kEf4lhKxKvFhG78mpzaOWzmJUcn1qc3HmpM379xvLvHFHi/QPJYgl/DmwP2AdB02HF5nXn8kWQe9fsTrBxsdY07o0cOG4jhGLtSTa8IaM5KHhI9KXE+EXwqD/EuSS1GNo1qxHqw/yCN9GKIdEr8Wh1+VUxvHvm+4HvicVKJOHyX+xc9zMQftLqM5SRypRB7q2Vj9wODgQ5DLyPdixIMxxCKHnrQzLtLVd4qx3iNKEGGMo2WL/D3kEmrCexTSdfVhfar3jLN8Ua4IC5ue0Zxat8gf5SUu80XrY4zKLF4xUa6xuMyv1+r3Y6Q7cRBhkDOyZ7ZWzrFcrVifr5XL84zprVyclzko3U597Vw+P+d1u+u+LvczDyX9lGpHLrxfn5pcevTRR4fs5PoguT5IfRYaG+O+UsyYTqziODefDyGVINJxhtEYx0fPCZrHx1gPDtQlIgNgn0Muab05jtYG3zvf+c77XkP4bKDrUnIpWidtikNuzwXbnTt3Ds82eG551atede83HuD72Mc+diCd+C0mkE2way7UkHU7FC/4gT3HQUmI65k9w3lOx7me5fc8Gc7zUef1szb6OQW58KtwKpkfOMZ4Tb03S1+OAKlarlfLk5FLSubgzaVFtvDNpyU9fkyPcnlMhIEtwrVs6uOYMpoDLzD+ooQXmOjDdPYC5PHXTC7xDZMvzMeQS3hTwBnti9uX2if9kKRjzAc9ethQHMfYc31DxzVEZBHW7YSR2lhHSsdGOYnxPLQzZklyKbonolr5vbBFcol/A+2Hf/iHB57+UMHrIElEiZpzTEkbJe2QeqDHcLjMbJmd8Ydk8gN2PcV1lqHeIy0iiT4sMhrTBomcvAdV8rrVxjF8HKuMcjGPS8TRpjk4znLRH8nWuvjaksVxLZGMYqL1OY7roXQ/9SjXWEzmRy5eq76/ZmMnDiIcckZ2tyHXWL6xXMxB6XOo3srl6xjTW7kwp8br2H3QW7kQq/E67s3FHJSIi2I9t6/L/czjuRwHHbnQZ6cml7C2iFzStWPM9UFGz0OZDfeV+2Dj6T7oHsO5UR+cTg5B17OFi+Kj5wTmiCTWgwN14fOmStiXIJdAIEVr494oweSEENZD0qhXIga5PRds+MPd+Ec4EEj/5t/8mwdev/CNJfjwPPXUU0/d8zMX6si6RW/22HMeOobN9Sm2COv5It1tUR7YcGRY2NXH6+f+od56FLm0HpkR3cdlO1+9T0Yu8Q2GJAsl7VOlx/fowIydXIfiaFPZMx/wxFFqDo7x4uMvSnxxUoKJNsroRZ2+a/y1OFybvsHzRfsYcol70COX2id+QFKJNyjq0cMGfSrRM/qGjmsgqeMkj+oc43paePojTGRTPP1Lk0voAb0nolr5vbT0r8Xxm0ouee9FkvcqakQ/SKUDyfTDP3zPRpzuqxNFqvsY+SMb7Dj0QUgfjDhWeTfkXozH0q+yB6P4tcd6jyhBxLHPTzskDtU5Rk69D48Zj+VCPT1/ZAMmygVsdiKmlYs96PPP1aP1aS5fi+uKjXJl18k8lJoHY+TitfLebEknDiIsckb2zNbKOZbLY13XOVu5PG5MP1Uurp/roXQ79WhdWUxmz3I5nji3RzrWhT47B7mEdSrBxHWr5Poge56HiMF9xTHkVB0xnBv1wRmRS/SpP8O5PXpO0Hw+xnpwaH1IzKgN4+hvLRHDP8vgueiHjNamfo75bMBcWA9IJX0mbo2JRT7PBRsIo5//+Z8fJZf+/b//9wciyteFGrJuh+LJD/SEHlN1xnpcZnec671xvTjm5/WzNtgPPYpcOh/Z4fd46evuxWbIJSVzWmN9E1Oc2jFukTmOPbeOFx9/UeKLEyQ+TKvOMd8g9EWdPv2D3h//+McP8bDxD3qDfCJWZSun4jjmB33qkdScvKHn/lqcvnnyRXsL5BKuu3ef/MMN3pjUFj1sqJ9j9IzuPfqYpA4kT9SJY5VjdvXrGDlcj2zArEEuaa2jWvm9pH/Q+4tf/OKh72HjH/TO/vdE7VvN6aQSdawLY5UY42Qu1IQ2SP/1VOJ0X50saunI737YePAhCDrG1CkjHLH0RTp9Y3mIW1u+773vPUyh9wjJoWMlcvIePFZmubg3mYzmzXJFWNqQn2OVWje1Y5ytye0el62PcY7nXJE9yxVhx2x6rXpvZmMnDiIcckb2zNbKeapcvoYxPVuXx+Ga3eZ6lkvrxRhK+lyPcjmGOmVvLsdH1xbZEId14XX9XOQS1gWCidfqkuuDnPJMjPtX8S3dfYzj3KiPE0ORjRhKYBTn9ug5gTGRxHpwaI3w7Kk6x0ouOWYuucTnXM4ByWcDrgsYEkZ/+qd/OrROxUa5YMPfWPqRH/mRA7nU+rU4POPg8xXXxnWhjqzboXh3f2DP/XCb6joei4M/wrvNdeZVu47pp3RfpvP6WRvUHYTS2AkcYyC1plF/lm1dYqTqe3x9N0Mu8U0mIoUiG/FTJPK0Ts/VwkZrmornfHgB8xclfaHJxvoCFMWDVML/FsdfwYHE11ppiwimsZxcC0kll/Sr1Jy8aaeSS3jx9ZMv/HPJJbxB9JxL79PYh53oQSiKwZ6jntx7rDMjeVp2+PREXYlnjSlpVzzHjFN9LXKJ/RXVivUgBhKkEv5OAP6+Ek/8kW/aIoJJ+1ZzkkxyiXmmkku6RoyjOSOyyG0tnXsHmT0UZXbGjvmn4ohfQ4JY6iWXxuaPiCj0gt+PPa8jwHhclMsxrkd5gFk6F19bfP5Iz9ak2N71HZMLsa1T18Mx1sVr9fsx0iOCwXHI6TbVPYfrih3LpViM5+byuDE9WpfHcG1ud70nF2Mos9xr5hqbO1sT4rAu9Nk5ySWuL5JcHySfeXok7jfFZbrbNYZzoz5ODEU2YiiBUZzbo+cExkQS68ER1Smz8flU/ZdELv2H//AfDr/y9s//+T8f+Ae98Y/R+BU5PCfh2QafHfC3mfDHv3md0TML31ex59HhduqUUQxskb/HRgwl86uuY/op3Zfp3jfoCT3qm0vHkxbR/Vq27dX14smljNDRN66ecUYWZbERPsPC3sLjxcdflPjC3ZLRi3qEB8n02GOP3fsDfdBBMoFs8j/63ZsT8/QQS8BpTr4ITCWXkIdv3pR80Z5LLkX7hTeNyA7bUvvEDzUqMS/16EGIPpV8IGPvYI0R+YN1z7GTJPJY5lO/Y6hvhVzifQGSCf/dLk7YoINkAuHkf/Rb+5Y1Zh7IiFxSv46ZC7VTu4+Jw33COZ04Qg63tXTgeWQPRZm9FYcYPYEdy8N8a0kSS73kUkQe0YY1cqwS+6L3YTZGLTIf7VkurWs0ZrzKVi7F9YyRiz0Y4f3aXI9isvU5dslcmjvLq9fq92OkO8EQYZAzstPmOVwnDvJUuXwNY3q0Lo/hdbjd9Z5cjKHMcq+Za2zubE2Iw7pwTxW5NDzwjMXaOCnE50W3U6d0nNujZyrGRBLrwcH9HJN8JlWJmGPJJeZDLj4bcF3wLfnNpS996UuHOZAT32LCZwQ9f+InfmLAP8I98cQTw9NPP32vNlwX6si6HYoXPA9kdrw246AkzqX7XSfe7dQpHed2+indn+m8fvYL9kiPIpe2R4JE93/Zjt+nVcklJX74gZ0kCyXtlJE9sgGf2cd8nEtllCuyMablI0ZlC48XH39R4otTS0Yv6i28+pRgAvFE39ScJJgYH0nNyZt2DrmE3Hyz1RftIpdefBBCv5Hw0Tc02kj40NdjJwYxOmYOysgH29bIpag/lWAi6QSc9m12fyrBFOWmjblQL9oiSZw+qDlxxJpncio+y3NpdiWWesmlsWtUUolj9IKSFtkYD6CZj/YsV08sc1AunYs9yPwql1of8vScOjfG2bU6TvVszcjFa43uSbc5weB+6MgZ2dWGPDzV7uNT5Yqui+uLfNG6FM8xr4d6by7EZTGZHTHRupbK5WvXdXCcXS/WhT67dnIJzyF6T/M5WG0c08faOCmEevGEjydtkLR5rNqLXPoeEYX+5HMG3v/Yr5Sf+9znBvyHQHi2f/vb337v7zD97M/+7AACijhK5sJeYB/14D6rpH/MRj/xkLDp4br7shxub+WJ5qXN8/D6WRv9vILxS1/60sNnGEr1MwZSa6q9XuPvvR5ULbZdi9XIJb5puCTJQpn51Z5hgYEvOjW+ZxzNEeVVW09eYqL89OGFyl+U9IUmG+sL0Jx4EEyvfe1rD/8SwTmOzck8KjUnXxDmkEsklPiCzDeSayGX+EYVPQjphySOseeoJ/ce/USSZyvyEsgl9CoIpje+8Y33PThp37LG2tcck2CiHknmQs9GftqI0311smiqzvvkmqUTS1PIJZJGvRK9wHuwJXE/t/zwZbn4WpDJKO/SudiD0VzZumiPYrL1Rdgx25xcWFuUF7l4rbwPj5XIeWwOxleuF/9uHesxJrdcL/TZtZFLfI49RvIeRH3WOKNnqtY8WM/Ye7X3IZ9L1X7sN5c0F58NuC7Mt+Q3lzgX/jbrm9/85sNnA/wPcvgHt3/yT/7JwYY1EEfJdaGerNs1P2u0ro3Xz9rMlVrTVp+Wb53Xi6rr8XU9Obl0zBvQtcbixWrOi5K+AM2Jj1741s7Jm3YuucQ38DHJa+ObO+Zljeb20VL7FH3AUVv0IKR+jnE9fl1bIZW4jkshl9gvKpe8F5gLPaRz+Jg43depZJLjWw9D1+CLiKUp5FKrBhHhhPuO9+Cxcsu52IPHXiPjL+Fa/X6cq+Na58Z6XOUqcsl7oqXP7RfE8Z6f+4w0N45zY/41zuiZqjUP1oOjVefIh+dStfP5s5UrWhufbzUXnw2Yi5ipEjk9l84zdcxc7J1D4Xb6Y27feM21pq0+Ld86rxdV1+PrWuTSCw/+/vfcN8i5cXgdnvOipC9Ac+L9BQ362jl5084hl6L1jtn45o55WaNz7xM/bGUyetiIsLieJa5rbj3WjOu9J6JacZ/HemPMv+S9wFy4rta8xOm+Olk0Vb/m57yMWOollyLyaMyG/oruxzm2LediD865rijmEq61dW9O8eFap+Bb2MpV5FKrP9w3t18Qx3t+zff2KDfnxvxrnNFzQmserGfsvdrrHul8/mzlitYW5eKzQStXFBfZ1sjF3jkUbqc/luob7k+rR8u3zmtF1XWZui5OLu30NeXoy+aLEl5Uppx8U54bH821Zk7euL3kEt6cjz39eo7ZrLl11jVEH7zUFj1sqJ9jzXnMNW01tqfWUa164qK+j2xe4wjTa+tdl8+51f25hHVpLcdIo14/cvIePFZuORdeq7e8vmNrz3jtkeiD2Bwbcs6Ji2IqV5FLUV9ktrn9ovdBRACtaePcfD5cWkbPCa05sB4cxz57KrmUPSdEa8uwXFfmn2JfOhffLy7huWCtNa5R01aflm8ZIqTquHwdFyWXcGPVefoa8EV9ydqvlZM3cQ+5tPXrmbq+3ppGDxvZXL05s/hLt0+p1dxrPUeNzzHn3PpsPa5qOe89aU9129O1bv1+veb1oc/0oXuN8TH1O+d9gLnXOqPnhNZcx9Rwamy0tqk5toA/Z+9s4frXWEOrR8u33utF1fb42up72507d4aXvuzl985bqmAMgAZ85jOfGeqsGszpgTFyac83d/Swsed6tK69anX8m0CrvuWr+lYPVA9UD1QPXHIPbPk5Yctru+Q9r7XXa1b1wPl6QLmiyeQSCYKSzw1Vg3k1uH379r3a1QvBiy8E9bDR/4JYteqvVd1fVavqgeqB6oHqgb31wJafE7a8tr31SV1vvTZWDyzTA0UuPTePFCkyaZm6Fbn04I1cDxsP1iR7wa9a9dcqq2HZq4bVA9UD1QPVA9faA1t+Ttjy2q61H+q66rWuemDdHliMXNJENX7bfb8+WPV4sR74I3pOymXk0mte85phr2f0sLHXWoxdd9Vqv/fJWG+Uv3qjeqB6oHqgemDLzwlbXtvUe4cf2Nf4+0NL5sQ6l8y3Ri7WsuS6JEjVd536Ku9x1K/FIVEdVYGsAuyPKeRS9r+hXLs9eti49muee31bqdVv/uZvLva/Q82tRcVN+1+l9lqv6tVl+qTquEwd93IfVr+cr1+28pwQ9fqW1xatN7OBiOIHdZAt33z8E5s8sTasE/J3v/D1TZ5cI+tZch0CpOq6Xl0XJ5e+/vWvD3VWDbwHilzqf7C6loeN7CFkSftWalUfHPr7e8n9r1zT6169Or1mUZ9VHZepY1Tba7RVv5yvX6LnhC3bLrH/i1xajqgqcmk90qMIpdPUtsilIsNOQgYWudT/YBU99Fziw8Yp1ryVWtUHh/7+PkVf1Bz5flSv5rWZ0jdVx2XqOKXml4ytfjlfv0TPCVu2XWKfF7lU5FIRN6chbi6hzkUuFblU5NLz53voiR4iooeeCFe254et1Ko+OGzrHqp7I9+P6tW8NlP6puq4TB2n1PySsdUv5+uX6Dlhy7ZL7PMil4pcugTSo9Z4GgKsyKW75NIP/dAPDTz1V7pgUx1j4jLZwkc+tXlOzkdMtB76tiy38s2lP/7f/8p9fxsHOk99Q6fN8YrhWLEcRz7aIImL8m/5oecS1taqre5Bax+yHLpfOl7yg8OtW7fu61Ffs+rA8lQ7xlEeYiOfx6vu+CxPZtdcc8dab+TQPeJYcztefdnYY5g3sjOH+2jvkV7XsZgMH9nVpuNjehV5/OSa1U4bZGZXjI4jvNo49txuZ07YiXWb6oxXqX6OKbM6RvGI4ToYT6l4HdMfyShXZIti1ea92+p3+jQ+GhOnkrjIBl9mZ9yYRLxisnyZXWN1nOGn2pEz6pdozyLbWmvSvBjrdXFMDHVI2jxG7T7GdbVOx0e6zw1MZuN6gbmE5xZdI69Lr4H1oM2vO7MzTqViOaafOiRtkJmdmKnkkvcC/kYTbPxbTTqmzWUPxmP4K2c9f3PJ14i/0QQb/1aTjtXmcaoT15JcYxEhpyFCqs7L17nIpZFvLkVkTmSbS+x4LteRV206njvnOeK2QC7xzZFvhtGbJ99EiYl09bX8c/PrQ0aN//rkB0Pfn0yfuj/Eu0T+6INDNm/LzoeQFoY+YDmGVD3Ko37Hax4fe64sT2b3fHN01Jx1Z7zrtENGePVHY4/x/NQzGeVs2byuLSx8GT6ycy9cIs8xvcp8XCt1yl47cS6n5nE886mdY0pgdBzpbnM8/FPrGOWIbMjt89NGGcVFNuIjObXfmYP9T91l5nc7dUrmcZ32TAKvMTpGDHVK5nGddkr3U6d0XGYnLuqXaM8iG3Nkc0y1M59Lz0O/26lTZjjax2TrmhmLuaL5IhtjIOG/tOeo7Jqm2rUOOvY89LmdOmWGg30OuUTiB/uPMaWPiXOpePdlOombXnKJJBDmwpjSx46jPkdyjUV6LE96VE1PU9Pdk0sga7LTiR2SMr0ET5ZX43XcM5/juaatyyKX+h9yL+1BaGvr5QPQmMwemMbs8Dsm+uAwNn/mx8NL5lO7447VNbeOkVdz6xg46pSMdZ32udJr7rrnHfNHeI3RMbDUVXLsuXr1qTXK8G6nDskx13RMr3ou6pScgzql26m7zPC9duYDXk/YVc/yMZ546o6H3evo+VX3fK28U3w6R7RG5ookelf7V8fAU6dkDtdpp8z8bqdOORZPv0vEaw4dA0udkvGu007pfuqUjsvsxHm/wB7tWWRjjmyOqXbmc+l56Hc7dcoMR/uYbF0zYzGXzwef28Z05qPM8FPtzBfJ6PoiG2Onzu145slkhnc7dUrmcx32U5NLqB8IJMqMTHI7iZsil05DMhSZs886755cUlImIm4yG+zZqTkxZg5K2hiveMXQrjYd038J8tzkEt8MKfFmqONIb72R0jcljvNRMofrWyNrLm09rOtU6fvAeLVzTElM9MGBvqmy9dCpuRx3rK65OWZOSth1rHpmZ65jpdfcdc8/5lc8sZTw6dh1+ig115Sx12wsNsNHdtoomfsUvco5KTm367RTut91x435gSeGUm2ej7pjEMuTmFYddS7ie20tvK7L87nOPJFk31ICo+NIZx7H0U6Z+d1OnXIsnn6VjKWET8eRznjH0U7pfuqUjsvsxEX9Eu1ZZGMOl5yTkn7qlG6n7tLx9LudOmWGo31Mjl0z56HUfG4b0zUW4ww/1e55VY+uL7JpjI65Fkr6qFPSPiYzvNupUzKv67CfklxC7ZQ0cl19Pi5yaZ9kR5Fcp933Ipfk1+Ii4qbXlhE8Ht+jA8MTeTVGx9mcW7RfIrmEN9DoTZRvsJTEUaqdY0jmoqTP9Usjc7a2Xt8H1rklfQ+IjeyRLfrgwBxT5ZSHTmB5+jxRHmIjn8dDJ45SbcTTR+l26sdKrzt0PT2/492vOrGU8Om4R9d8vWOv2Vhchp9iX6pXe+cEjufY9cFPbE9+xSo+Gkc2rkd9kS3yt+oY4SObXy8wPLkOl5onG3uM6+xtSvh1nOmO8byMA44nMR5LnTLD0R5JxlICo+NMd0wrN32Moey1Exf1i+4fcZGNPkqsIVrHFDtzqWQ8JX3RXPBldsZFMrq+yKaxnIcy8tHmGNeJo3Q/dUrHZXbiIsnrg9QzwqoNc0XzuZ06peaIxsRREgOdY0jqlPS5DvspyCXWzgkj6C2f4otcOi3JUKTOPutd5FIHuaREj5M9Y0SOk0HUmZM687jO+TI847Yuz0ku6RthNtY3Ur6BUmoMbSrdT52SWOqUbqeuEtjoVMzc8dg63O/zuJ86JfHUKd1OvVcij5+InZvf47iOKfbogwPzTJV4SOqJcdyxus+p+bIxYtwHnafnPEb3/ZiqZ3NrHh0DD11PzeFY9fWOtXY9MRl+in2pXo3mdNuY7tfcg1eMjpGLOqSe6vMxdcVzDB/9HFNmdURsFEM74+fIKAdtlGN5tW+zMXKoT3NmdmLcT53ScZmduExqXDZGrPo0V2Ynxv3UKR2X2YnzfuF+URLnOu2R5JyUxFCndDt1lxl+qt3zqh5dX2RjjM6t48gPm2NcZxyl+6lTOi6zE+eS10ZJv+u0R5JzUhJDndLt1F1m+Kl2zbsUuYS68FRSaKnxEuQS1wfpf1NJfdHY8ZHONRYxs09i5hr2vcgl+d/iSOQoUdND9ijxM4bX3FPmY1yUn74ty2sml/QNFmO+QVPST53S7dRVAhudipkz9jUgh9tc93ncT52SeOqUbqc+VXo+jx/zA59hxuzu9w8OvpYpOh5IevCOO1b3OTVfNkaM+jRHZlfMlLHX3GPd77rjqStOx/RTqo9jSmKmyqk1yvCRnTZKrm2JXvWcyN1jizBcV5TD8a5rbBTv/rl6NK/XERjHqc19U9cyFj/m53zas9kYWPUxtmVXjI6Zh5I+6pRup55JjcvGiFWf5srsxLifOqXjMjtxUb/A5/vmOuMjyTkpiaFO6XbqY5LxlMRTp3Q79UhG1xfZGKtz6Djyw+YY1xlH6X7qlI7L7MS55LVR0u867ZHknJTEUKd0O/UxyXhK4qlTup065FLkEkkk1IfjJSWJG8iI2FEb1kCdY0rYdUycyx6Mx3CN10Ay1DXskyArcsnIJSd8Tk3mRPOpTcdbJpN8becml/DmqCfeDLM3zMyub6StMeMpiaVO6XbqlMC1TuKmSp+f8W53nThK91OndFxmJ26q9HweP9ffioOPfkrM6x8cfC1TdDyM9OAdd6zucyKfn8CMzcM8jqN9rtR6Rznc73oUAxtwfkZYzUc84yN8j21qjTJ8ZIeNdkqsaYle1XzI6Tqv3e2uE0fp/jGdcZSKx7h1MqZHal7iW3WM8G5rrU19nG9Mev4Mz95VCaz2t+qZPcvvdsZT0k+d0u3UM4k4P4HN8mX2Vn71MZ6SPuqUbqeu/eJ7pbqOGUuZzTHVznxjknkpiadO6XbqkfTrc91jMIefihlbg/s1FmP3U6cknjql26mr9GtTXccag3E2x1S758105qUkjjql26lDrk0uoV495xgRReKmyKV9kh5Fdp1m34tcsr9pRFKEJA4l7XMl8kSn54vmU5uOPXbL+jnJJX0D1DdJHQNDnZJxc/UsLrNzPkrgWidxU6XPz3i3z9WzuMzO+Y+VY/nH/JzfcW6nnxJ+/eBA/FyZPXS6fW1d169z6RgY6pSMc532uVLrjRxTdc7rcbR7TsdRz6Tm6R1nNTrWzniXWNcSvcq8vE7XM7vj1ta5Dpc+L/yRzeNUb9UxyhXZNF/PGnpyeM6Wzl4GRseqZ3bm7fVnuMzO/D1Sc+h4S9eh/eL7qLqO/dqnXluGZ95ef4bL7Mwfydb1RXi1+XzwuW0pPcuT2XWdHPu1qq5j4imzOabax/K5f25+5FmbXIpII9QwsrdsRS6dhlwoEmffdd49uTRG1rgfes+pRI/naPk8N7Aar2PNs/XxFsklvCHizZQn32hbdvoUS9uUPMRCei7Pp1gfR7FjNs+ha1Cf51EcfRl+qp35jpXZvMjr61csx8RRp6Sd64OdY0j94KD2OePsoTOyw8bT51oCz5yei3P22pnnGOk1Ry7uT+aL5ouwxLkvyq8YHTPHFOn1Y+yxdo3XMfIv0aueE7qfei300UbpeWAnNvMxlrKFJ8Zlb26PU93rqOvwMeKiOTVfD6YnTBJXUAAAIABJREFUh+ds6d6/Ub8jPrPT53Nk+Kl2z5vpyKu+OfN4DuSbmifDIxf7JdtD2in1enSczTHVzuvT3LQxl/pog+yxKwbX1HNqTDT2uYHJbFyv55mCZw6Pyew6V7aPtFNqjI6zOabakdPXTxtzHTMvY+eQS9oTIISgkxjSMW0uezAeM5Vc0jX6r8LBp7/SptjWWGOiMddYBM2+CZpL3v/dk0tjpMxSZI6TRtTH5odf16DjntitYLZCLvGNcK6M3qTn5rqkuL1ed+8e8YNDL34qDg8qU2Om4NfOP2UthX3xj0ivVYe1e7V33efsuWhu2FqnX9fUOkZzes4xTGt9Y7E+1xL6tbwvnOI6evvlVPt4imteoseWzLGla762fZ5KLjnpAx01oV3HtLnswXgMiRvIiNgZs2FOYnRM2xKSa7xkcqHWvm9irMgl+d/itkLEXOM6roVcWvJBp3Kt+yH6lPXt/eBwyjXVXNfTX0vuZfXqMn1RdVymjkv29pZzVb9Uv2y5P49d2xLkkhNBa+gkbuaSS0uQR2M5uMYiaPZN0Fzy/he5VOTScAoyq8ilerA69uFly/H1waH6e8v9qWurXl2mV6uOy9RRe/Oax9Uv1S/X3N9FLn393jeaxsijMX+RS0UqXTKxhLUXuVTkUpFLz9dDzzU/9Jzi2uqDQ91Dp+izJeaoXl2mV6uOy9RxiZ6+hBzVL9Uvl9Cnc9dY5FKRS5dOiNT6lyP1ilwqcmmz5BLerOqsGlQPVA9UD1QPVA9UD1QPVA9UD2y3B/jhHN+82fKJdW55ffXNpeVIDvZkydPWdFFySZPV+G33fS2s6vG2Acdzzz1333n79u17et38p735q95V7+qB6oHqgeqB6oHqgeqB6oHqgeqB6oHqgSV6QDmPO3fuDC992cvvnbdUwRgADVCiQO01LmIp6oEil+pFa4kXrcpRfVQ9UD1QPVA9UD1QPVA9UD1QPVA9UD2wrR5QDuBocunw1ZT6URUIKoBGw6GEJMb6zSX3lX7/t7yqHlWP6oHqgeqB6oHqgeqB6oHqgeqB6oHqgeqBLfbA4uTSKf7nsZrj6yf5O0lL1nkqufTWt751qLNqUD1QPVA9UD1QPVA9UD1QPVA9UD1QPVA9UD2wzR5QkqvIpfqD3ichquaQS8EXoMpUFeiuwJNPPdmNLeD6Faj9WL/Gx85Qe3RsBefHV+3n1+4UkbvYn1u3TlHK1ebYxR6tVr3lE9d+LF/TKGPVOarK6Wwgu578o6/t+kQNilwqQukkhJJ+82lNcunDH/7wcKnn6V7+9jdTveFua89rP7a1H9Fqao+iqpzGVrU/TZ3nzrKL/SlyaW57VFxQgV3cM8F1n9pUdT51xe+fT79JtVeSabfk0g/90A8N0UkCBD6OI8nYyAcb/S6J9/yOU535GEupmGhM3Bbl2uTSl7/85eHSThBidaxXgXrDXa+2czLXfsyp2mljao9OW2+drWqv1djeeBf7U+TS9hrvgle0i3tmA/tTdT7vJvCbS3/y1/7K6LeXgNGzRUYpjmPHw+421RnnuMyusVPGuyWXIsIFBA3tOqaNUn06pl9l5s/siI18kY3zqE/H9G9RnppceslL/s8BpxNOkQ2YyB7ZFAt/dHLOlg+YJcilm+9/ZGid+pKb4YiBv3UcG4/cY3Po/NF86h8b/9UffM8DENh4PuBsGL72nlsDT4XRBjnl+F9+6f8aeGocbZBTjx//8R9/IAQ2nuqkLYpR3JLjJ+vXFJcs5yq5ao9WKWtX0qp9V5nOBtrF/hS5dLb+usaJd3HPbGDjqs7n3YRecskJHpA3kY2kTsvH2BbGfdQpe+chriWLXJJfiVNiRsckZ2CbYkec4hlPybwuNYa+yBb5WjjityCvlVwikRTJiJxS2xLkkr6k3twlmtQ2NkYMDx3TpvJYP3KN5Zgyn2J9HBFITja57jmoO3FEnTLD0e7SiSPqlMS7TnskSRapz4kj6pTEuk770vLJIpeWLuni+WqPFi9pd8KqfXepzgLcxf4UuXSW3rrWSXdxz2xg86rO592EHnLJCZ2MqFGcjiM8/C2M+6hTMqfrtE+RRS5NIJfmkDIZkdQigSJfZON61Kdj+rcojyWXXv/61w9+8uUEJI2TOyRxKOl3HXbaKFvYFp5xlJ5PYzF2csmvD3rvcTOBJNKcU+IUqzk4bvnho1/HjI0k8ZGvx+bk0Zie5cxIpMye5aE9I43c7jrjM+kkUaZn9izvUvYni1xaqpSr5ak9Wq20o4mr9qMlOitgF/tT5NJZe+zaJt/FPbOBTas6n3cTzkEukRCijIgg91GnZIzrtE+RRS51kksgbXpOJXKU6NExMK5ncbT34ls45tqCXIJcAhnDU4mXtcglJ4Ncj8gjYHhGfrVF5BKvD1KvMXvpvBHSRjGZXTEYA8dDx7Sp7PH7vK57vlbOlk/zZOMxMsn9WR63k1SipN912l1mpJHbXfc8rjtplPkd57rHLaU/WeTSUqVcLU/t0WqlHU1ctR8t0VkBu9ifIpfO2mPXNvku7pkNbFrV+bybsCS5pIQOSB893Qd9jBiK4j3GdZ2nd1zk0l1yyUkZ1yNCpoWJfGrTseamnZI+12GHrXUydovyXOTSGCGkZI9jx3TERqeSS+6nD3IJcslfUm+ELHJfpCtex2PYOf4opmXDevRsYSOfk0djepTDbUog6Rg41z2WOkgjPdXOMeSS5JISSDrGPK7rGpYcP1nk0pLlXCVX7dEqZe1KWrXvKtPZQLvYnyKXztZf1zjxLu6ZDWxc1fm8m7AmuaTkDkkgyjFySXGOhU9PnWfOuMilCeRSi8iJyJ85pA7zUDKH67RDqk/Hitna+FrJJSWLfOzEFfxqO5ZcujHyJdOzl13g9dB4tXOsfh8D4/kYN1d6PtfH8o6RSe4fy+fk0Zie5XPSiDol41ynPZMZSeT2MT3Lf6z9ySKXji3h6vG1R6uXOJ2gap+WZhOOXexPkUub6LVrWcQu7pkNbFbV+bybsBa55CQPySJKJ4wyPO0aR9tYDsW1xkUuGTlDEmYqSRPhYWudnIvSc6iuY+Ip1adj+rcoz0kuKamj5A7trW8XEaMS40inndLn8phjyaVjX05vAnLpmJxRPtjGzt45Pf9YnJNHY3ornxNJwLrN9Syfk0bUKRnnOu2ZdNIIuB5bhMnmOMb+ZJFLx5TvJLG1RycpczhJ1T4sy2aMu9ifIpc202/XsJBd3DMb2Kiq83k3YUlyKSOAlAQCxs+I+PFcrjMms9PfI3dPLmVkTGSHrXVOIXGy/JpDMTpWDMbq07HjtqQvQS75H7zmywlIGhI6lE7sUKd0oodxkZ0xlMS6Tjtl5FdbRC5l18hrjeRNQuBEWNoQ40dkc0xL74nvwWRzTI0dI5Pcn82bkUZudz3L56QRdUrGuU57Jp0kcp1xbneduKXlk0UuLV3SxfPVHi1e0u6EVfvuUp0FuIv9KXLpLL11rZPu4p7ZwOZVnc+7CT3kEgiaiMRxm+o67o1XIiiLz+waO3W8W3IJJEyLiIl8kW0uYeO5XGde2inVDtvYSfzW5LHkUuulo4dcImmk5I6OSQgRp/oUm8ZF+dXm5FLrGjPfTUASEZv5ptqZDzKLVYyOHe+6Yn3sWNcd77qTR2O6x1PPSCO3u854l04aUack3nXaM+kkkeuMc7vrxC0tnyxyaemSLp6v9mjxknYnrNp3l+oswF3sT5FLZ+mta510F/fMBjav6nzeTVByCcSNn0rUtHyK41jxtKmEn7qO1cYctEHSFsUorne8W3JpjGxxMgf4JYmcKH9rTVPxrVxb8F0ruQSyyE8STEokRbZTk0s3d7/hlL0Mwz929GA0x1S8xmLMNc/J42QS8sHG0+fKdJBGfhKrdtp6JIgjnoqnbSqxhBxOEkH3k3Opnba15ZNFLq1d4qPz1x4dXcLZCar2s0t3ksBd7E+RSyfppb1Msot7ZgObWXU+7yaQXOolYtbCLUUUzVlfkUt3/6D3FgiXPa3h1OQSyZwtyyXIJbyk3sz4tbjopRh5xo5sLto9nvZMOn5J/ckiM5Ys59G5aj+OLuHqCWqPVi9xOkHVPi3NJhy72J8ilzbRa9eyiF3cMxvYrKrzeTdhK+TSHFJoqZgil4pcGs5BahW59OIfAVeyayly6bwvq9udvd5wt7U3tR/b2o9oNbVHUVVOY6van6bOc2fZxf4UuTS3PSouqMAu7pnguk9tqjqfuuL3z0dy6X/9/z5+71fUSNpkNth5EjtHRvk1D+dQSX9ko2+qLHKpyKWrJJdA1Fzief9LVGlLVqDecJes5vG5aj+Or+HaGWqP1q5wnr9qn9dmC55d7E+RS1totatZwy7umQ3sVtX5vJswhVyKyKDI1kPukBxqYbPcbne9lTPyFblU5NLVkUvnfVmp2bdagXrD3dbO1H5saz+i1dQeRVU5ja1qf5o6z51lF/tT5NLc9qi4oAK7uGeC6z61qep86orfP18vudRL4PTiQPKMYTO/212PCKSWbVVyCb/6VGfVIOsB3I7PPffcfeft27fv0+lHo9ZRFTimAvWGe0z1lo+t/Vi+pktnrD1auqL9+ar2/bU6B3IX+1Pk0jla62rnXO2eQZ/y1OpF/UtcJjW+Nc5ye4zO4z7VM9xU+zAMD9TZ1zoj572lRrnuOe8Oovwe5zFXpBe59LVhVXLphRdeGHDWURXwCoBwQm+QPKIscskrVfpSFXjgDXepxJVnVgVqP2aV7aRBtUcnLfd9k1Xt7yvH5pRd7M+FfyDcxR5t7s7IF3Ty/Zjav7144Byb2bQcHkOf26lTOi6z38XdV+cR7L3rGMP5GqAjZixO/TpmvqlyiRxT55yIV3IJ3wDyk9/4OfbbQcyjcixn71rG8uic0bjIpYlNU/BlKrAUufR93/d9w5xzmauoLJdUgfvecC9p4Ve61tqP7W9s7dH59qhqf77a98y8i/25gA9yrb3axR61CrAx3+L7gf7MTlz71P7txXNOr6/Hj+mMz3BT7Xfz3VfnLEc2d8vuuYB1W0t3H+eaIpEjyfMnf+2vTMm0GlbJJSdelLTRseMy3ckhz+G653G/6hjr6bFT9JOSSz/wiocHP1fb3Uq86QosSS594xvfGKacIKPq2F8F7nvD3d/lb+6Kaz82tyUPLKj26IGSnMxQtT9ZqWdNtIv9ST7EzSrYGYJ2sUdnqOvcKVfdj6hXI1tr8T14Yig1n9vGdMZmuKn2u/nu1dnj4Xeb69maotjI5vnGdM7XK5GPp8XsgVwaI3iULBrDwp/hM3tPTmBORi6BVPqdZ1544IT92OPWrVuDnq18wOlBnZI+zedjYBxPm2NVZ+6Sw+FvcS3xa3EgikAs3blzp+sEtsilfXbgvTfcfV7+5q669mNzW/LAgmqPHijJyQxV+5OVetZEu9gfe16eVagzBu1ij85Y36lTr7ofUa9GNi468kU24imJoaQd0m1jOmMz3FT73Xz36uzxY2sEnifXRhnlivLRNjUP5xmTzEsp+Gsll6YQPVOwF08uZcQSySb/NpPq0jeLDJ0Uok4ZTRL5Ihtj1adj+kuuQy5997vfHXCCaMrGRS7tt/vuveHutwSbuvLaj01tR7iY2qOwLCcxVu1PUubZk+xif7IPlLOrdtrAXezRaUt61Gyr7Qf7lJKrdJ12yMgX2bKYCOu2MZ25M9xU+9189+rs8dF1R5glcZ7fddagVyLez7uxl0YuZeSOE0Sut749NIZ1P3VK5nad9l55km8uzf120q2XvKrZbiBuWmcU7GQPdcqeGGB68S1cNNdebEv/Wlx9c2kvnTP/Ou+94c5PUZELVqD2Y8FirpSq9milwnakrdp3FOmMkF3sz7EfBM+4P5h6F3t05hpPmX7x/SDJoItQW6t/I19k89zUI6zbxvQsF+MoHZfZ7+Lu1dlx8LvNdZ8riiEm8nm+Md1zAT/nHIbhEsklkDUgcvTsJXAinJNCrvt8mmOpNSDnycglfksJ8rEvfHf40M13hvc/9a3h1x//+vCu3/vq8NBHvzL83If+ZHjTo18afuq9nx9e/+7PDmPk0v09+SLRpLZo7GQPdcqeGGB68S1cNNdebGuQSzc3NwPO+ubSXrpo2nXee8OdFlbolSpQ+7FSYRdMW3u0YDEnpqraTyzYieG72B//YHjiGh873S726NginTB+1f2IejWy8Xrd5zpxKoHx0/1TdGJ9buqUjsvsd3H36uw4+N3mus8VxRAT+TzfmK65esbI5+fduK2RS0rcYG17OHnNV0EuKYGj46hP6YfkCRztrRj19eJbOM23t3GRS3vb8fNf77033PMvpVZQ/6p8ET1Q98z5tqlqf77a98y8i/3xD4Y9hdkQZhd7tKF6jy1l1f2IejWycZEtHzEtGcW7bUxn/gw31X433311znL43BnO7YyjdH9Ldx9zTJHIoafEXiq5hEtQ4kkuqcuexTIP/dR752PcFHlWcunDn/vL4YOf+fbwyOPfGN79qeeHX/ndPxt+6bEvD2/+wLPDT7/vmeENv/a54bXvemr0m0tKDmnRpthJ/lBqHoxpp6TfdWJhz07Gllznby71fHPpv//3/15/0HunDXjfG+5Oa7Cly6792NJuxGupPYrrcgpr1f4UVZ4/xy72Z4kPg/NLfHTkLvbo6CqdLsHi+6Ekg49xWd6/jsn0npJ47mg+2jiP5vV4Yo61+z/ceb6xNXEdXGsUTx9zqU6b56HdsVN15g3WBRJkCwe+tUOShTIjaLhe+qFzzOtRSZ/jptoZTzkWT/+Y5PWe/JtL+JW43/rst4f3f/pbw3t//88PvxL39o/wV+L+8PArcT/58NPDa945Ti6hKFMOEkKUiOWY0vPRTkm/67RrTh8rZu/jJb+5BMIIvwpX5NLeu6p9/Ys/2LSnK+9IBWo/Rgq0AXft0fk2oWp/vtr3zLyL/Qk+wPXUZiuYXezRVordsY6T78dW+/fWrcPf2Oko2SzIA3WeW4e5cdGql8qFPEkuEB9bONYgl5zUwXW6jdffY2c8JWNcp71Xno1c+vDNd4YPPv0XwyN/8I3h4U89P7zjYy9+a+ktH3x2+Jn3PTPceQ++tfSZ4dXv+HTzm0sgd3pOFIoHCSFK2DmmJFZ9tClGx/RTqk/H9Jdc9ptLJJd6/qh3fXNpv933wBvufkuxiSuv/djENjQXUXvULM+qzqr9quU9Ovku9if5EHd08U6UYBd7dKJaLjHNJe8HPlwveeCPJ691LFbnLd7/jTUtvUdz9wfkEk+SLRE5g/xcM/20ZfpSds5DOZaX/jHJ6z3pN5c+Kt9aevEPeT8/PPSRrwy/8Nt/PLzp0Re/tfS6X/3s4VtLr/zlJ5rkEgriR4vIcR91l5qTPtpU1zH9lOrTMf0l1yGXvvvd7w44W3/Qu8il/XbfYm+4+y3holde+7FoOVdJVnu0Slm7klbtu8p0NtAu9qfxQe5shZ8w8S72aEI9zg295P3Ah+olj4sgl5a84BPkWnqP5i6595tLyM81k7ShLdJ1PfS7VIzm0jFiqFMyj+u098qzkEuHv7V0+NbSN4d3f/J/3Pe3lt74yBfvfmvpqcO3ln7sbf/trORSRgrRTnnYobvfgIJt7CR+73LJX4t79tlnD4RSfXNp713Vvv5LfrBpX9llems/tr9vtUfn26Oq/flq3zPzLvanyKWeVihMZwUu+Z7hB/LOSx2FFbk0WqLJgKX3aPIC7gb0kEuAkrDJxrwe4lRqTMtOHCWx1CndTn2qPDm5hL+19KGb7wyPPvE/h8O3lj7x1eGhj35l+Pl731p6ZtBvLf2jhx5flFxCAaODJBFlhIlsU/FRjj3bliaX8I2k3vP7vu/79lz63V77JT/YXOOm1X5sf1drj863R1X789W+Z+Zd7E+RSz2tUJjOClzyPYMP2UseRS4tWc3vETVL79OcVZ6TXHIyCOtnTdQ3ZlfslPFJyaVbL3nVgSiaI+dsbMVsvwJLkksgi6ae269QrXDpClzyg83StdhCvtqPLexCew21R+36rOmt2q9Z3eNz72J/ilw6vlEqw70KXPI9ww/o9y7myEGRS0cW0MKVADHXydVecskXxh7za1GdY8Ry3JLEURJLndLt1KfKk5JLWHwdVQGtwFLkkuascVWgVYFLfrBpXdel+mo/tr9ztUfn26Oq/flq3zPzLvanyKWeVihMZwUu+Z7Bh+wljyKXlqzm/UTLspmnZ+shl5S0wQzUdcyeU5nhMjvzUTousxM3VRa5hIrWcbYKFLl0ttLvduJLfrC5xk2r/dj+rtYenW+Pqvbnq33PzLvYnyKXelqhMJ0VuOR7Bh+ylzyKXFqymt8jZ5bepzmrPIZc8vUruaNrcbvrxB5j19jecZFLrHzJs1SgyKWzlH3Xk17yg801blztx/Z3tfbofHtUtT9f7Xtm3sX+FLnU0wqF6azAJd8z+HC95LElcmnNtSxZs1YuJT9auFP4ppJLuvapY1zP1Jg18UUunaLDao60AkUupaUpx0oVuOQHm5VKcta0tR9nLX/X5LVHXWVaBVS1X6WsiyXdxf4UubRYv1SiYbjkewYfyJc81iR0ptZ5zbUsWbNWLiVMWrhT+E5JLul1b2Fc5NIpOqzmSCswh1zCC2adVYPqgeqB6oHqgeqB6oHqgZV74G/8YD1z1XNn9cBTTx6+HdLzegOiZgwHDM8x7Cn8PWs+xTqOmUOJlWPyHBuLD70gl7KT5Iuul2P6XNIPqb4xu2JPPcb1P/fcc/dOfObneefOneGlL3v5vfOWKhgDQDCkJ3rhhRcGnDx+4BUPD37SV3JfFUC/oDe0ZzC+ffv2AzbY0ah1VAWOqQDeNOrYTgVqP7azF9lKao+yyqxvr9qvX+NjZtjF/tQ3l45pkYq1ClzyPYMP8j0HiJqxg8RSD3YsV+TP6qxkhMattQ6dY+1xdm1rzxvlx+fVMTIH6x3DwO846pTMQZ2yFcuYNeXJyCWQSr/zzAsPnLDPOW4Fb3pq0zHzw9Y6iXOZ5VLcWN4sx1icznFN4yKXrmk3L+Nasjfcy1j99a2y9mP7e1p7dL49qtqfr/Y9M+9if4Ln7J7abAWziz3aSrE71nHJ+4EP7T1HD1FT5FJPJadhsD88p0Uuj94iuaSk05qkEnOfhFzKiCWSTf5tJtWzbc/IGuLH/MT1yKm5jsFHsT1rvDRMkUuXtmOXv95LfrC5/Oo/eAW1Hw/WZGuW2qPz7UjV/ny175l5F/tT5FJPKxSmswKXfM8cQy55bJFLnQ0zAUZiyWs9IcVi0CXJJZI1lLg+jlWqnbWgX320rS1PRi7N2bVbL3lVGgYSZuz04DnEDedALo4pPT/1aJ7IFuFbOOKvQRa5dA27eFnXcMkPNpdV6b7V1n701emcqNqj81W/an++2vfMvIv9KXKppxUK01mBS75n8AG95/BvLvGDvsYXudRTyWmYqM7TMiyH7iWXdM09ZA/wES6zA9vyRbmWsp2MXOK3lCAf+8J3hw/dfGd4/1PfGn798a8P7/q9rw4PffQrw8996E+GNz36peGn3vv54fXv/uwwRi55Kygxo2PiYGudxKlkHkr6XKcdMvJFNsaoT8f0X6Mscukad3Xb13TJDzbbruy81dV+zKvbKaNqj05Z7fvnqtrfX4+tabvYnyKXttZ2F72eS75n8CG95yhyqadKy2OwPzyXzz4tYy+5pETOGAmU+TP7OYklzL0rcsnbY4zIcb/qOu7J24tv4XyeS9aLXLrk3bvMtV/yg81lVry96tqPdn224K09Ot8uVO3PV/uemXexP0Uu9bRCYTorcMn3DD7E9xxFLvVUaXkM9ofn8tmnZewhl5RYGiOCMgIps3s+1sXnXFM/C7n04c/95fDBz3x7eOTxbwzv/tTzw6/87p8Nv/TYl4c3f+DZ4aff98zwhl/73PDadz0165tLIGd4ajvQNiYZA1x00E7pGNop6XcddthaJ2OvURa5dI27uu1ruuQHm21Xdt7qaj/m1e2UUbVHp6z2/XNV7e+vx9a0XexP8hy8tb3I1rOLPcoufoP2S94PfEDXI/vVtiKXtEr5OKtfHtH2kEDxfWpHreNdklzC9UQkUGaPiCXGt2KIWUqenFzCr8T91me/Pbz/098a3vv7f374lbi3f4S/EveHh1+J+8mHnx5e885xcikiZtgqEZlD35qS81JyLtdph1SfjhVzbeMil65tR7d/PZf8YLP96k5fYe3H9JqdOqL26NQV/958Vfvv1WKLo13sT5FLW2y9i13TJd8zTlpk5EiRS33tmdWvL/pBFPaH54Pe01p6yCUnelwnyXOsXeN1zPxryZOTSx+++c7wwaf/YnjkD74xPPyp54d3fOzFby295YPPDj/zvmeGO+/Bt5Y+M7z6HZ9ufnNprFUykgb26MzyRdhWbs2jOB0rBmP16dhx16QXuXRNu3kZ13LJDzaXUeFpq6z9mFavc6Brj85R9RfnrNqfr/Y9M+9if4pc6mmFwnRW4JLvGXww1yMjR4pc0irl46x+eUTbg/3h2Uau7wWxwrNF3nC9kMTpGDbFcNyyM49KjVP7muOTkksflW8tvfiHvJ8fHvrIV4Zf+O0/Ht706IvfWnrdr3728K2lV/7yE6Pk0lQipoWPfJGNbRn53Ka6jpmDUn06pv8aZZFL17ir276mS36w2XZl562u9mNe3U4ZVXt0ymrfP1fV/v56bE3bxf4UubS1trvo9VzyPYMP6Hpk5Mgx5JLPofNNGWd1Jsng8/iap8w1F5vVb26+7Nrm5jsmDsTKXOIG1zE3dktxJyWXDn9r6fCtpW8O7/7k/7jvby298ZEv3v3W0lOHby392Nv+20WRSxkpRDslGxZ6z0n8tckil65tR7d/Pdkb7vZXfp0rrP3Y/r7WHp1vj6r256t9z8y72J8il3paoTCdFbjUeyYiLjJyxImaKbHALnFkdY7Wgvl8zUusYSxHVr8jvAMCAAAgAElEQVSxuMyfXVuGX9N+DLm0JYLomLWcjFzC31r60M13hkef+J/D4VtLn/jq8NBHvzL8/L1vLT0z6LeW/tFDj3eRSy2CJmqeDB9hYZuKb+XJfHu0F7m0x10/7zVnb7jnXdV+Z6/92P7e1x6db4+q9uerfc/Mu9ifIpd6WqEwnRW41HsmIi4ycsSJmimxwC5xZHWO1oL5fM1LrGEsR1a/sbjMn11bhl/TXuTS1w6/Fvjcc88NPPGZn+edO3eGl77s5ffOW6pgDADBkEwCCf2FF144nLde8qoDUTRHrtkAlft8FWB/aM9gfPv27fv6iH7crHVUBY6pQPaGe0zOip1fgdqP+bU7VWTt0akq/eA8VfsHa7Ilyy72p8ilLbXcxa/lUu+ZiLjIyBEnaqbEArvEkdU5Wgvm8zUvsYaxHFn9xuIyf3ZtGX5Ne5FLJyKX1tzEyn2ZFShy6TL37ZJXnb3hXvI1XfLaaz+2v3u1R+fbo6r9+WrfM/Mu9qfIpZ5WKExnBS71nomIi4wccaJmSiywSxxZnaO1YD5f8xJrGMuR1W8sLvNn15bh17QXuVTk0pr9VbkbFShyqVGccq1SgewNd5XJKuloBWo/Rkt0dkDt0fm2oGp/vtr3zLyL/SlyqacVCtNZgUu9ZyLiIiJHIpvG3nz/IwNOxUHnAawfwE49sjrrWphT10LbKeSx83pdoms7xXVEcxS5VORS1BdlO0EFilw6QZFrivsqkL3h3gcq5WQVqP04WalnT1R7NLt0RwdW7Y8u4aoJdrE/RS6t2kN7S37J90wP8RMRJhHp4bibu6RTzxw9PZPVOVoL8jlR0zPHsRivwdR8vubs2qbmXQJf5FKRS0v0UeWYUYEil2YUrUKOqkD2hntU0gqeXYHaj9mlO1lg7dHJSv3ARFX7B0qyKcMu9qfIpU313KUv5pLvmR7iJyJMItKjF4f9dhKlpweyOkdrmTtHzzpamKgGLbz7vC7ZtXncKfQil4pcOkWf1RxBBYpcCopSplUrkL3hrjppJU8rUPuRlmYzjtqj821F1f58te+ZeRf7U+RSTysUprMCl3zPXCK51EvAOK5zO4+CXTu5BIJpzyQTrp3/IRckPvPzXOx/i2MH/sArHh78pK/kvipQ5NK+9nsLV3vJDzZbqN/Sa6j9WLqiy+erPVq+pr0Zq/a9lToPbhf7U+TSeZrrSme9tnvGSRknTG6+/5Eh+kaN47DdikMcjgjX0xqss69P59A8jlPfWuMp19ZD7GXXttb6W3n3TCo9+UdfG3CejFwCqfQ7z7zwwAn73OPWrVtD69S8jqMPdhyUavcYxeiY8RGeOErmH4uJ8Bp76eMily59By9v/XzDvbyVX+eKaz+2v6+1R+fbo6r9+WrfM/Mu9qfIpZ5WKExnBa7tnnFSxgmTm5nkEsqJWM/XWeYBdY5iMwLGr6N3nmNw0fqyfEUuvUjYkLi5BHkScikjlkg2+beZVM+aDfYWAeM+1aOx2sZyj/k91xR8FIv4azuKXLq2Hd3+9Vzbg832K95eYe1Huz5b8NYenW8Xqvbnq33PzLvYnyKXelqhMJ0VuLZ7xkkZJUxu7n77KCJ0FMfS9eKIb0nUuXeOVp41fdH6svmKXCpy6d7v2JE8eOGFFw6/Cpc1Tct+6yWvarmPIpdA4vDEJE7q0KeSONqyxXkuxvXgo9gs7pLt7A/9nUyMb9++fa+H1AcWtI6qwDEVuLYHm2NqsYXY2o8t7EJ7DbVH7fqs6a3ar1nd43PvYn+KXDq+USrDvQpcyj0TkRn3LkIGIEj0UMLkpsglLc0DY63VA04z+H5ksY6zNCdT69fiTvRrcf7Npce+8N3hQzffGd7/1LeGX3/868O7fu+rw0Mf/crwcx/6k+FNj35p+Kn3fn54/bs/O6xJLrHLSOZQup26S8erP/JFNsaoT8f0X6Mscukad3Xb13QpDzbbruJyq6v9WK6Wa2WqPVqrsuN5q/bjNTonYhf7U+TSOVvs6ua+lHuml6RwcgkbRttNkUvN/s0IoijI9yOLdVyU6xS2IpeKXLr3jSUndVz3hmz5I19kY0716Zj+a5RFLl3jrm77mi7lwWbbVVxudbUfy9VyrUy1R2tVdjxv1X68RudE7GJ/ilw6Z4td3dyXcs/0khQkknSjYLu5SyzBjlw8iYvIEWJ0bsUhp+ZlLsi/+oPvuXdCR501lthoDvpcIn7NI1pfNp/WBJgs1nFZvrXtRS6diVz68Of+cvjgZ749PPL4N4Z3f+r54Vd+98+GX3rsy8ObP/Ds8NPve2Z4w699bnjtu57q+uYSyJjs1AZyDH0kcyjV7jHUgXG8xkX+CM98mWTOa5RFLl3jrm77mvCGW8d2KlD7sZ29yFZSe5RVZn171X79Gh8zwy72p8ilY1qkYq0Cl3LP9JIUGQFzI+QSShDl81hgeLJsEYmC3MxPUol4SNo8FnbmhyROJfN4rNo5PlZmc0R5sV49oljWRHHnGhe5dAZyCb8S91uf/fbw/k9/a3jv7//54Vfi3v4R/krcHx5+Je4nH356eM07x8klb5yIwHGM64yhdP9UnXkoGe867ZDq07Firm1c5NK17ej2r+fJIpc2tUm1H5vajnAxtUdhWU5irNqfpMyzJ9nF/hS5NLs/KvDBClzCPaMEzINXMG65MWIJEU6OwAaCRI9o3ohEQQwJIY3XMeqsscDjiObQOObVWPX7mtU3dZzN4bWK1hzFRnWfuqal8EUunYFc+vDNd4YPPv0XwyN/8I3h4U89P7zjYy9+a+ktH3x2+Jn3PTPceQ++tfSZ4dXv+PToN5e8EeYQM4yh1JywtU7FYuw5VNdxK66F87hL1otcuuTdu8y1X8KDzWVWdt6qaz/m1e2UUbVHp6z2/XNV7e+vx9a0XexPkUtba7uLXs8l3DMRmTGl6DcBuRTFO1ETzRuRKCSKWvOgzlFsNAfWhlyaL4oFztccXVevLZsDa9QjWrPH6to19lxjkEs8n/yjy/uf3pZYM65f/1MufObneefOneGlL3v5vfOWKhgDQDCkJ8L/FMf/Le53nnlh+Kh8a+nFP+T9/PDQR74y/MJv//Hwpkdf/NbS6371s4dvLb3yl59YnFyaSty08JHPbarr2BtefTp23DXp6Bf0hvYMxvW/xV3TLm/rWvCGW8d2KlD7sZ29yFZSe5RVZn171X79Gh8zwy72p8ilY1qkYq0Cl3DPRGSGXUaq3nQSS0jgRE00r5Io/FYRYknAZPOhzhrLBUdzaA6McUax0ZqZd47M5uC1MWe0Zo/Va2DcOWV9c+nE31w6/K2lw7eWvjm8+5P/476/tfTGR75491tLTx2+tfRjb/tvTXIJJEzPqQ02lbhp4d3nOuelnVLtsI2dxF+bLHLp2nZ0+9fzZJFLm9qk2o9NbUe4mNqjsCwnMVbtT1Lm2ZPsYn+KXJrdHxX4YAUu4Z6JyIwHryS23EwglzxDNK+TKIwhAZPNhzpHsT5HFq+x/KYU5oZ9qUPn0Jy8tpZNY7Nr0PhTj4tcOiG5hL+19KGb7wyPPvE/h8O3lj7x1eGhj35l+Pl731p6ZtBvLf2jhx5vkktzmmUqkTMV31oTctXxvQoUufS9WtToNBXAG24d26lA7cd29iJbSe1RVpn17VX79Wt8zAy72J8Lf27dxR4d08Qnjr2E/XACprdEN0cQS5gjmldJFF2HEjDRvKhzFKtzRHGcQ2OBI8EE+1KHzqE5scavvefWA6diNLZ1HRpzynGRSycil2695FUHomiOPGVD1Fynq0CRS6erdc30YgXwhlvHdipQ+7GdvchWUnuUVWZ9e9V+/RofM8Mu9qfIpWNapGKtApdyzyh5Y5eQqjcLk0sgdJRE4cRKENHmc6POY7Eew1yQUSzXo7hjxjoHySS9NtoyifjId8yalootculE5NJSG1Z5rqcCRS5dz15eypXgDbeO7VSg9mM7e5GtpPYoq8z69qr9+jU+ZoZd7E+RS8e0SMVaBS7lnplKLt0cSSyhTEqs6DeFSMKwlIqjzedHnRkHySOKpU9lFBvZNGbqWPORJMrWR79KxKvO8dR1rIEvcqnIpTX6qnJ2VKDIpY4iFWTRClzKg82iF73hZLUfG96cu0urPTrfHlXtz1f7npl3sT9FLvW0QmE6K3Ap9wxIjinHzcLkEudWAoa2jIDRNaDOU2KZmzKKVZvOxZheSRJI88HGo7f2iN/qUeRSkUtb7c2rX1eRS1e/xZu7QLzh1rGdCtR+bGcvspXUHmWVWd9etV+/xsfMsIv9KXLpmBapWKvApdwzvQQHLu9mAWIJeSLSSAkYljLC0Ye14ESdPRb2VixzQHqs2/DNKn67SuNaY5JKlNEciO+tPeK3ehS5VOTSVnvz6tdV5NLVb/HmLhBvuHVspwK1H9vZi2wltUdZZda3V+3Xr/ExM+xif4pcOqZFKtYqcCn3TC/Bgcu7WYBcAlETET8RARPhrMyHNWks19gTi1way9xuQ86MYCKBlMlsDth7ao+5sZ6tHkUuFbm01d68+nUVuXT1W7y5C3yyyKVN7Untx6a2I1xM7VFYlpMYq/YnKfPsSXaxP0Uuze6PCnywApdyz/QQHLi6m4WIJeSKiB8ndFjRsfWhzlFsNAdzqoxiIxuuPyOQIrvOgTFy+tG6Nsy3RM19zqV1kEs8n/yjrw17PHH9zz333L0Tn/l53rlzZ3jpy15+77ylCsYAEAzpiV544YUBJ48feMXDg5/0ldxXBdAv6A3tGYxv3779gA12NGodVYFjKoA33Dq2U4Haj+3sRbaS2qOsMuvbq/br1/iYGXaxP0UuHdMiFWsVuJR7pkVw6CXdHEku6Td/IuInInQw/9j6UOcoNppDr4eEkMa2bPRFUvNm4x5yCTXCeWytszWsYcfn1T0SSnrNJyOXQCr9zjMvPHDCfuxxK3gDdBv07MT8vXiu1fHMkc3h+DGc46fm5zq3Kotc2urOXO+6LuXB5np34P4rq/24vx5b1GqPzrcrVfvz1b5n5l3sT/Bs3VObrWB2sUdbKXbHOi5lP8bIG17qzRHkkhJLyBcRP0rycE5iVfcx6hzFRnMg1skhjaUvstGHOpAE8rW0dOT0g7XXfD35vZ6e95R6kUsn+rW4jFgi2eTfZlK9pyEyIiaLnYpnHo3TceSnrUdOzaV4HffMtRVMkUtb2Yn9rANvuHVspwK1H9vZi2wltUdZZda3V+3Xr/ExM+xif4pcOqZFKtYqcCn3DAkOW/596s2CxBIT+7xK6BAD6Ti3oc69sSSIKJErio1sXJPWYgrJg5w8SCbh2jSH5gaWOI+jvgXZSy79rb/1twae/NYPdZXwqc4xY1zSD6m+qXaNnTo+yTeX5n476dZLXtXVJxHBEtmYLPJFNuIpFaPjyE9bj5yaS/E67plrK5gil7ayE/tZB95w69hOBWo/trMX2Upqj7LKrG+v2q9f42Nm2MX+FLl0TItUrFXgUu6ZiLyxS5n9a1pKnHhO1zNCJ1qf2lDnsViSSZQ6dxQb2TTmRsg2YEkC9Urm0uuATfMSA8m8atvKuIdcioifiMAhjjLCqM1x1CmJpU7pdupz5cnIJX5LCfKxL3x3+NDNd4b3P/Wt4dcf//rwrt/76vDQR78y/NyH/mR406NfGn7qvZ8fXv/uzw5rkEskYyjZjNB50qayB+8YjW+No7jIxhzq0zH9lyCLXLqEXbquNV7Kg811VT2/mtqPvDZb8dQenW8nqvbnq33PzLvYnyKXelqhMJ0VuJZ75kaIlM5LP8CmEEsIyAgdJ2CAVRvq3IoloUTp1xDFRjaN05oA64euz32qK05zKmbr4x5yyUkbJ3nop52S9kw6jjol46hTup36XLkrcsmJGNV17I0b+XptnivSp+ZSvI6j3Fu1Fbm01Z253nXhDbeO7VSg9mM7e5GtpPYoq8z69qr9+jU+ZoZd7E+RS8e0SMVaBa7lnrmZQS5NJZZQuozQUQKGJVYb6xyRPCSUIFuHx2Zr0Rysi8cCo+vTmNaY+VqYLfqWIpeU+NFxi/BxHHVKxlKndDv1ufIs5NKHP/eXwwc/8+3hkce/Mbz7U88Pv/K7fzb80mNfHt78gWeHn37fM8Mbfu1zw2vf9VTXN5dIrlCy0cZ0x0V42NzucdQhic+kYjlmfkq3U4fM8tKu2K2Pi1za+g5d3/r4hnt9V3aZV1T7sf19qz063x5V7c9X+56Zd7E/RS71tEJhOitwLffMzURyaQ6xhJJmhE5E1KiNdXaSp5dY4ty6rdlaFMO6+LzA6Po0JhszV+bfsr2XXAKxwzMicZT4IY4ywsOmMapPtWf5e+0nJ5fwK3G/9dlvD+//9LeG9/7+nx9+Je7tH+GvxP3h4VfifvLhp4fXvHNZcukcjeiEUbQGYiiJcZ12SPXpWDFbHxe5tPUdur718Q33+q7sMq+o9mP7+1Z7dL49qtqfr/Y9M+9if4pc6mmFwnRW4BrumZsTEUsoaUboRESN2lhnJXmmEEucW7c1W4tiMEZ9dF76dX20teTUOrdyndrXSy4pUePkjxJDPo505vI81Ckdl9mJmytPTi59+OY7wwef/ovhkT/4xvDwp54f3vGxF7+19JYPPjv8zPueGe68B99a+szw6nd8evSbS06sqK5jbSzYo1MxOo6wWW6Nw3gM537VddzK28J53Jb0OeQSXjDrrBpUD1QPVA9UD1QPVA9UD6zcA3/jB+uZq547qwekB26+/5HueuAbS8e8Rimho3lA1LgOm9uJUWKJtjGJuRWTrUUxGN/cJZfcnq3NccwR2S/Bhs/ZIFayMyNrppI8jmdet1OndFxmJ26uPCm59FH51tKLf8j7+eGhj3xl+IXf/uPhTY+++K2l1/3qZw/fWnrlLz+xOLnUImIiX2QjQdPy9WI8h+o6Zj7K/5+994mR7bjOx2aXxPHmtwy4UHaJdwGcQcIfAoMwmBVBxKufF9lMrE0egiiCQJuCHViOJ/CDZUAiZMByoAVlQzIEsylb8iMomKAsSDQk0BKfKT6+J7IlP5kSpGcCFsmxRFk0xxV8PfP1nD59qm7d2/dP3VvnApdVderUOae+U3371sfqebJP1tk/h7ILuTSHeXmM5SKALya/ykHA81FOLmKReI5iyAwvd+yHx/gQD1Xkx08uHbJEfKxCYAmfmXXmyaWuP4WTkElCR8pB1MiLxBLlEmdJLMkxTXX4llcsFqnDuh4LOWOjTqrMxThlY8o+ECttSZm2JI/Wpz8tZ5ul1ovJqde1HJVc2vytpc2ppZ+EJ7/x1s7fWvrwje9enlq6szm19P5PfjNJLsVIFcpZygVmydhv9VmymD50c+7YeC3XvnNs6zG0WWLp5FKJWVl2TPILd9kzncfsPB/l58lzNF2OHPvpsM/xXEV+nFzKWQquk4nA3D8z6xGJJUCaS+jEyKWuxBJ9y7TmxsKxGqtcckmPkzHMpZ5DLjWROm37SQLFxrWV017XcjRyCX9r6dn1O+HpWz8Nm1NLX/9RePy518PHt6eW7gZ5aul9j7+YJJeaFlmMaImRNDF7bfVjdtrKY/G3tVOqvpNLpWZmuXHN/cVmaZnxfJSfUc/RdDly7KfDPsdzFflxcilnKbhOJgJz/8ysM8ilPk4sZcK5VZPkkiSUWN8qtqjo00eHkEsyvlQIOfimxpfSl0MugbQB4cNbkziaDErpa13aPFSuY2rTHoVcOrr/kQ1R1KUsZbF4HP0i4ORSv3i6tWYE5v5i0zzDeWl4PsrPl+douhw59tNhn+O5ivw4uZSzFFwnE4HUZyb3ZEumq97V1oUSS5ioJG9IKLHsCkRXckmSUMRMxheLh7qx/jnJc8mlNmRNTFcTSDG9seWjkEtzWhQe6zgIOLk0Ds7u5QqB1IvNlZbXxkLA8zEW0t39eI66Y3foSMf+UASHHV9FfpxcGnYRVWY99ZmZO7k0xYklLB+QSJK8QTuFc+6S64Ncgq/1fTd24rP8Q2dJ15jk0tikUa4/J5eWtKJnNBcnl2aUrIWE2scX7kKgKGIano8i0pAMwnOUhGfQTsd+UHgPNl5FfpxcOniduIErBFKfmUPIJU2EXHnsr7ZOECBTEks8oSTxS+Gci4jGVJ5Ikja0Hvq0DNjJ+OT4FK5Sb051J5fe2Pxreffu3Qu8sefnfXp6Gh548KHtfSQbqEOByihpBCXa5+fnm3tOi8JjHQcBrg+5ZlC/du3azjpiPz6sfjkChyDQxxfuIf597C4Cno9dPEpseY6my4pjPx32OZ6ryI+TSzlLwXUyEUh9ZizywZJZrjSZYekcIlsXRiyRUGKJuUmsUjjn4qAxRZu3tKH10KdlwE/GhzZvaWspdSeXnFxaylqe3TycXJpdymYfcB9fuLMHoaAJeD4KSkYkFM9RBJgRxI79CCAf4KKK/Di5dMAK8aEagdRnRpIPGIc2b21HtzWZofsPba8j5NLYJ5ZIJsmSc5P4pXCmftuSxJLGWrdh15IhPuAYw7JtPCXrO7nk5FLJ63PRsTm5tOj0Fjm5Ib5wi5zoTILyfJSfKM/RdDly7KfDPsdzFflxcilnKbhOJgKpz4wkR2COxJKWW64sMsPS6yJbF0os6blInFI463G5bWDMW46xsLdkMj45fol1kEu8c/9G0dL0MH/+8ggl9vy8e/9Z3Hveuwr6XuLC8jk1I+DkUjNGrtEvAkN84fYbYV3WPB/l59tzNF2OHPvpsM/xXEV+nFzKWQquk4lA6jOjyQe0eTeZt8iMpjG5/euJySV5Sgn12CXxS+EcG98kJ7GksdZt2LFkMr4mX3Pv95NLI55cAqn0t3fP927Iu1xHR0fBumkLffKydKWOrGNcTJ96LHN80JbUrb3u5FLtK2D8+Q/xhTv+LJbj0fNRfi49R9PlyLGfDvscz1XkR71H5+BSkk4VOSoJ8IZYUvnQ5AOJJS23XFhkhqXXVraekFjSpFKKWMK8JE4pnNtiQH1gzJsylBb2lkzGJ8cvse7k0kjkUoxYItmkTzPJdpuFJwkfWY/ZIOnDMqWn+1L2ZZ+saxs1t51cqjn708x9iC/caWayDK+ej/Lz6DmaLkeO/XTY53iuIj9OLuUsBdfJRCD1mdHkA9q8pXmLuLBkckyqrv1K3bVBLo3xd5Y0sSRjitXlPFI4x8Y3yYExb6lrYW/JZHxy/BLrTi6NSC51WUBH9z/SapgkcmQ9ZkTqyLrWt/osGcfJPllnv5dh+68Jyt9kou7/WpyvjqEQGOILd6hYa7Dr+Sg/y56j6XLk2E+HfY7nKvLj5FLOUnCdTARSnxlNPqDNm+ZJbmjyQrepn1NqvxyzNogl9A1JLnUhlRivLFM4S722dQvnXFkM57YxzEHfyaURySWeUkL55X94Nzy7fid84c7b4S9f/Jfwmed/FB5/7vXwR8/+MHz06e+F3/vcd8LvPPlqGJJc0qSPbssFbPVZMo6RfbLOfi+dXPI1MD4CQ33hjj+TZXj0fJSfR8/RdDly7KfDPsdzFflxcilnKbhOJgKpz4wmH0gsSTmIDN7SpUVwyP5UXdqXemuDXJoDsYQ5pHCWc2xbt3C2ZJbdGM6W7txlTi5VSi6R8EEp79iCpr7st2Tsl32yzn4vnVzyNTA+AkN94Y4/k2V49HyUn0fP0XQ5cuynwz7HcxX5cXIpZym4TiYCqc+MJh/Q5k3zJJY0oaHb1G8qaV/7XhvEEmwNQS71dVpJzjWFs9RrW9c4x/Jh2dUYWzpLkTm5NBG59KVv/1t45ls/Czde/HF48oU3w6e+9s/hE1/+p/Cxv/5++P2n7obf/Ytvh9/6zJ1WJ5c0iYM2byxY1rUeF3OTXPfrtvaBfn3Tl5dOLvkaGB+Bob5wx5/JMjx6PsrPo+douhw59tNhn+O5ivw4uZSzFFznEoEmAiH1mbHGalmMzNCkR25CYJ+3HLM2yKW5EEuYRwpnOc9D67F8WHZ1Li2dpcicXJqAXMJP4r746s/CF15+O3zu7882P4n7k6/wJ3H/uPlJ3IdWr4QP/tnh5FIfC5UkEkva1G3KUco+WZc6tdf9D3rXvgLGn/9YX7jjz2yeHj0f5efNczRdjhz76bDP8VxFfpxcylkKrnOJQBOBkPrMWGO1LEZm9EkurScglvpeQCmc+/QVy0efPuZoy8mlCcilL63fCc+88q/hxks/DqsX3gyf/urFqaU/fOb74Q+euhtOP4tTS98Kv/7pl7NPLlkETkwGeezWi1jbkG1ZT41L6elxNbWdXKop22XMdawv3DJmW34Ung/PUfkITBehfz6mwz7HcxX5cXIpZym4ziUCmgzSwKQ+M9ZYLYuRGXMjl+RP4TRGfbRTOPdhnzZi+WB/rSXIJd63X3sj1Hhj/vIf7MKen/fp6Wl44MGHtveRbKAOBSqj1IbOz88D7ve8dxXwh7yfE6eWLv6Q95vh8a+8Hv74b34QPvr0xaml337i1c2ppQ/86a0scilG3sTkscVu6WuZbMu6tin7ZF3r1dzGesHakGvG/7W4mlfE8HMf6wt3+Jksw4Pno/w8eo6my5FjPx32OZ6ryI+TSzlLwXUuEdBkkAYm9ZmxxmpZjMywyCVLpuNBW/pYj3BqaWhiCXNK4Wxh0FUWy0dXe0sZ5yeXRj65tPlbS5tTSz8JT37jrZ2/tfThG9+9PLV0Z3Nq6f2f/GaSXAJpkyJuUn3WAtb6us0xlLOUcsiaburXXjq5VPsKGH/+Y33hjj+zeXr0fJSfN8/RdDly7KfDPsdzFflxcilnKbjOJQKSqLFASX1mrLFaFiMzLCLJklkxSR/rgcmlMYglzDGFs4VBV1ksH13tLWWck0sjkkv4W0vPrt8JT9/6adicWvr6j8Ljz70ePr49tXQ3yFNL73v8xSS51LQINfkztX6T/9r6nVyqLePTz3esL9zpZzqPCDwf5efJczRdjhz76bDP8VxFfpxcylkKrnOJgCRqLFBSnxlrrJZZZHnJ98MAACAASURBVIYlg++25NJ6YGIJMZFcsrDpU5bCuU8/Mez79DFHW04ujUQuHd3/yIYo6lLOcWF5zM0IOLnUjJFr9IvAWF+4/Ua9XGuej/Jz6zmaLkeO/XTY53iuIj9OLuUsBde5RECTQRqY2GcG43jLMdqeRWZYMtgojVwai1jC3GM4S2z7qMew78P2nG04uTQSuTTnReKxD4OAk0vD4OpW4wiM9YUbj8B7JAKeD4lGmXXP0XR5ceynwz7HcxX5cXIpZym4ziUCTWRQ7DNDYkmP1+0YmWERSZCt77uxuZkgSw8+oKevn/uFz2pR5zaJJZRjXDGc+/Ydy0fffuZmz8klJ5fmtmYXE6+TS4tJ5WwmMtYX7mwAmThQz8fECchw7znKAGkgFcd+IGB7MltFfpxc6mm11GGmiQyKfWYwjrdEqskedSVptL7vxubUEokP6EBGOUp5wYeWob8vcmlsYgmx375zW05xsDoxlvgP5mxGhjW51PS3mJfWj38dDxjIf7ALe37evf1rcTNaEx7qSAg4uTQS0O5mi8BYX7hbh15JIuD5SMJTRKfnaLo0OPbTYZ/juYr8OLmUsxRc5xKBJjIo9pkhsaTH63aMzIB8LU4ppfQQqtTVPtDfF7EEWySXLiEapYjhPIRzJ5b2UbXIpXD3A6GGG0SZk0v7a8IlIyHg5NJIQLubLQJjfuFunXolioDnIwpNMR2eo+lS4dhPh32O5yry4+RSzlJwnUsENFGjSZ7YZwbjeKfA1PaoqwmOXL31fTc2fmkH5dyJJcwhhrOcZ191jX1fduds5xBy6eGHHw68SUaxLUv0yTbrHGOV0NFyjpN9Usa6HhdrO7k055W7gNidXFpAEmc2hTG/cGcGzSThej4mgb2VU89RK7h6VXbse4Wzd2NV5MfJpd7XzZINTkEurS9/BidxzSWXMEbGPASxNNbfWZLzH/PZ5OSSRP6iDnKJN07xgHCJkTFSLgkeyNlmKXWtekoPfbo/1tZyy1dMNgm59J73roK+99PikhoQcHKphiyXNccxv3DLmnmZ0Xg+ysyLjMpzJNEYt+7Yj4t3W29V5MfJpbbLomp9SdQACE3yxD4zPLWkx2swtT30rzPJJWssxtNnn8QS7E7xczjiFcOZ/X2WTi7to3nIySVJ2pDkYSn7rHqTnu7XbdqMydmfKkcnl0Aq/e3d870b8i4XJmDdtIU+eWld9EkdWWefHiN1ZD2lTz2WqZigI2+pu7S6k0tLy2j58xnzC7d8NKaP0PMxfQ6aIvAcNSE0XL9jPxy2fViuIj/qPboP3Ma0UUWOxgS0wReJGqppQieWj67k0vryj3NrgkP7RTyWDHL4XhKxhDnFcGZe+iw19n3anqutKcilHEJI6+g2SaOYnP2pEhzGaH9zKUYskWzSp5lku83ikgSOrGsb7GOJflnX+mxLHdR5s5+l1EvJrD5rLPWWVDq5tKRszmMuY37hzgORaaP0fEyLf453z1EOSsPoOPbD4NqX1Sry4+RSX8ulCjtjkktr8a++aYLDIpIsGZLSN7EEm1OeWoL/MZ9NGvsqFnrDJA8hl0Ds8CaJwzZLymWJPtm26lqH9lhyDNssKc8pwWGMSi415MLsPrr/EVMeE0piRta1PvtYol/W2YZM37Sl9SnnWNmOyagjbck6+5dYOrm0xKyWPacxv3DLRqKM6DwfZeQhFYXnKIXOsH2O/bD4Hmq9ivw4uXToMqlq/JjkkgRWExwxIknrLZFYAi5jPps0pjIvtdYPIZckgQNyB22W7NNtS4e6stTjYu2YXNqK1cFhjEou8ZQSyi//w7vh2fU74Qt33g5/+eK/hM88/6Pw+HOvhz969ofho09/L/ze574TfufJV8PU5FLqg5Eigaw+S0b7sk/W2b/EshO5hBcdvx2Djmvg9n/7C45dR+yG+Nx5Psp/nnmOpsuRYz8d9jnPuxry8/Wvfz347Rj4GihrDTQ9n8Z8Nv2HT/33/l4t36tD2PwxbxAsvDf7+rsfaDxZpAkbTfKwX8t1m3q61HpNbY7XepRbJea6SHIJE+MtSRnKWKIPdV6yrvuoI0va0eNiYy092pN9ss7+JZadyKUlAuFzGg2BMf9vzmiTmrEjz0f5yfMcTZcjx3467HM815AfkApnZ2d+Owa+BgpZA/hMNl1jPpv85NJ+Nvo+uaRJHE326LbWZ1vrNbVj4yi3SnAYk5FLX/r2v4VnvvWzcOPFH4cnX3gzfOpr/xw+8eV/Ch/76++H33/qbvjdv/h2+K3P3Gl1ckmTMk1tLAfoyFsuESnXdY6V+qxD1+qnnHrU0bZlW+oure7k0tIyWv58xvzCLR+N6SP0fEyfg6YIPEdNCA3X79gPh20flmvIj5NLTqw5uVjWGnByqY+n97A2upJLMbInJie5o/sp16XWi7Vjcm3PaoPDmIRcwk/ivvjqz8IXXn47fO7vzzY/ifuTr/Ancf+4+Unch1avhA/+2TjkEpeYRf6wzypj+pSz5Fjdphyl7JN1qbO0upNLS8to+fOpYTNQfhauIvR8XGFRas1zNF1mHPvpsM/xXEN+JLn02NfeDkPcb775ZrBuJzXKIjU8H2Xkw8mlnKfztDpdySWQNSB2eEvyhjJN/HCM1G0ro21pgzLLn9TTdXAYk5BLX1q/E5555V/DjZd+HFYvvBk+/dWLU0t/+Mz3wx88dTecfhanlr4Vfv3TL2efXLIIGS3TbSw9KZN1uSwht26pw7q2IduyTn2Wsk/W2b/E0smlJWa17DnVsBkoOwO70Xk+dvEoseU5mi4rjv102Od4riE/Ti6VQSg4seN54Bpwcinn6TytDsgl3iBaNvv6Dn9zSRM3ue22hFCu3Rw9zHV0cuk5cWrp4g95vxke/8rr4Y//5gfho09fnFr67Sde3Zxa+sCf3soil2JkjJbrNpaelMk6l6UlS/VpfdmWddpgKftknf1LLJ1cWmJWy55TDZuBsjOwG53nYxePElueo+my4thPh32O5xry4+SSkxokNbwsYy3wM/n222+Hd955J5yfn4d///d/33lkjfls8r+5tAP9pnHIyaUcAqdkHXAYo5NLm7+1tDm19JPw5Dfe2vlbSx++8d3LU0t3NqeW3v/JbybJJUwgRcToPurrkstC60NuyWL6MV3KWcrxkDXd1F9a6eTS0jJa/nzG/MItH43pI/R8TJ+Dpgg8R00IDdfv2A+HbR+Wa8gPN7IgFob4SRxsWj+Jg8zJjDLIDM9DWXnAZ/KVV14J3/ve98Jbb721IZicXOrjid6fDSeX3tic3Lp3717gjT0/79PT0/DAgw9t7yPZQB0KVEZJIyjRBqOK+z3vXQX8raVn1++Ep2/9NGxOLX39R+Hx514PH9+eWrob5Kml9z3+YpJcaloGmsyx9KWOrEvdGPkjdXLqMfs5Y5eow/Uh1wzq165d21lH7MeH1S9H4BAEatgMHILP2GM9H2Mj3t6f56g9Zn2NcOz7QnIYOzXkx8mlsogFJ3o8H/hM3rhxI3z1q1/dEEw/+clPNvts+ZQb89nkJ5ck8hd1J5dGIpeO7n9kQxR1KffT5pIlIODk0hKyOK85jPmFOy9kponW8zEN7m28eo7aoNWvrmPfL559W6shP6WRSzevH++f9j++Hm7in4lfnYTj6zf3TzzdvB6O+SsB6l7+s/Krk+Nw/eYuYWH6uByv7UP3ZCXHr8IJfcTiUf+k/b6NS3vW+NVJfP5nN8P145OwUvadkJL5mX8dn8lPfOITG4IJJ5iQXxzikNeYzyYnlyTyF3WLXIodVFmifLSfxe1D75LaEXByqfYVMP78x/zCHX928/Po+Sg/Z56j6XLk2E+HfY7nGvLTF7n0odU3oz+ra/OzOBAxmuDZkicWGXO2CidHVwTShjg6WW0JqBi5tEsYxQmJfWJoYHJpjzhahZPtfJxc2q6FPZziOZzbGHwmH3vssbBarcLLL7+8+Wncu+++u/PIGvPZ5OTSDvSbhiaXQLY03fgj3NBhqfW1XLepr+Vss9R6MTn1upbAgL88Qok9P+/efha3D71LakfAyaXaV8D48x/zC3f82c3Po+ej/Jx5jqbLkWM/HfY5nmvITx/k0n/6P/7v8Iu/+Ivh/33qOybBNCi5tEc4gYC5Ipti5FLsNIEmnfoil2L+okQayZOd+Tm5NDeiqEu8+Ex+5CMfCU888US4deuWk0s5D+uRdZxcGulncSPn1d3NAAEnl2aQpIWFWMNmYE4p83yUny3P0XQ5cuynwz7Hcw35OZRcIrH0fz62Momltn/Qe3PyiD9x0z9VEz8ZIymzT/6cBUkoyTo3+tYY9unSiudoyJ/FkVTalJpM0u3lnNbRuNfcdnIp5+k8rU4uuYRTQ7x5QohtllLOOkr0yzbrWs42S60Xk1Ova+knl6Zdg9V6d3Kp2tRPNvEaNgOTgdvBseejA2gjD/EcjQy4cOfYCzAKrNaQnxxyCT95s372lkMsdSGXSBztEQw7p3guiBWLKJKEkqzTnkkYkdDa/gQtZn/3Z3E8kRSN+ewsWDFuYjHmwxjtfieXdvDZIeKWQ7Q5uVTgl4EKKZdcksQNSR6W7GObpZazzTKm11ZOe11LJ5fUovDmOAh0IZfwMue3Y+BrwNeArwFfA74GfA34Ghh2DeSQS7/yv/1f4X/8n35ph2DKJZaGJpf2/8g3CJj0z+LaEBT7xNAuuZQilegnRWZFx+OUFk9IbUkUJ5eI6ZJLfCYf/eCjm7+79Pm/+nx4/u+eDy/demmyvRH+5pI/h6+ew9hBg1iJ3TGyRpM/1KOcpZazzTKm11ZOe13LUcml97x3FfQ9DpXhXkpDoAu5VNocPJ55IYAvQL/KQcDzUU4uYpF4jmLIDC937IfH+BAPNeQnh1z68BdfD//z//KrW4KpDbE0OLnU5g96i5/V8cRRrOTfXuqDXJJECOxFCaVLEmlDRu0RSziZ4+SSxHKp9dJOLh3yDF3qWBArbUkZTf5wPOUstZxtljG9tnLa61qORi6BVPrbu+d7N+SHXvgC0FdMFvuysPRhM6av/cm2ZUvLYnapx1LabRNPF/upMbF4dHy5bSeXcpFyvb4QqGEz0BdWY9jxfIyB8mE+PEeH4XfIaMf+EPSGH1tDfnLIJRBEJJjwh7txp/7GEvTl3fYPepvvqfi5WuxnZDevh2P+rE2RMtbP4qKkhGHfPHVEH4Z+1LYgjlLk0urkKBypn+Zd2XRy6QqL5fwMTs/JyaXhn+2Hesghl9qSPTF9Tf7E9NrKtd227VHIpRixRLJJn2aS7ZwkW8RHroz2+9C3bMkvQvbrMte3pUdbbfty9VN69N2ldHKpC2o+5hAEatgMHILP2GM9H2Mj3t6f56g9Zn2NcOz7QnIYOzXkJ5dckgRTG2IJ49qQS3qjvdPuQOZY5JJJGOk/Hr79KVqCxGiKp8NJqZ357sXg5FIan0Su9rAsV9fJpWGe531azSGXQNaA8OEtyRvKLEKIfVpft2N6beTSZtv6aORSl8Qd3f9I1jASICjlrQfLPqtu6WsZ2xgfu6w+S8bxsg913uxnKfUoY9m2L1c/pUffXUonl7qg5mMOQaCGzcAh+Iw91vMxNuLt/XmO2mPW1wjHvi8kh7FTQ37akEvyNFKbeonkEn/2dhBZ0UQu9U5oOLl0UL56z8cwBJWTS8M8z/u0mksutSVsLH1NQFk6U8hGI5d4Sgnll//h3fDs+p3whTtvh7988V/CZ57/UXj8udfDHz37w/DRp78Xfu9z3wm/8+SrIYdcIvnBkgtEtylvW8KOdcfs0C9L6um2lut+3Zb66NM3+63SsmXJOFb2yTr7+yidXOoDRbfRBoEaNgNt8OhT94f/1X/R2pznozVkow/wHI0O+dahY7+FoshKDfmplVzCe6958ydvOUSEk0uhBrJn7Dk6uVTk18FOUGOSS1MQRzk+F0MuIbOSCJF19plfFupLZGeFqIa2qbo3Tamj/eXoU0faoQylJbdkh4yR9mRd2jy07uTSoQj6+LYI1LAZaItJX/pOLvWFZFl2/DMzXT4c++mwz/FcQ35mRS7lED6u44TPzNeAk0s5T+dpdZxcemPzr+Xdu3cv8Maen/fp6Wl44MGHtveRbKAOBSqjpBGUaJ+fn29u/TeXvvTtfwvPfOtn4caLPw5PvvBm+NTX/jl84sv/FD72198Pv//U3fC7f/Ht8FufudN4cskiPihjmVpiKR305dzSvmWPMpZd9XNiSfnQfbqNuJp8yNgPrXN9yDWD+rVr13bWEfvxYfXLETgEgRo2A4fgc8hYJ5cOQa/csf6ZmS43jv102Od4riE/Ti4N89OmsU+7uL/l5NHJpZyn87Q6Ti5NQC7hJ3FffPVn4Qsvvx0+9/dnm5/E/clX+JO4f9z8JO5Dq1fCB/8sTS5Z5IhcTlb/kOSJ5S8VT1t9aatNnX5YcqxuU45S9sm61Dm07uTSoQj6+LYI1LAZaItJX/pOLvWFZFl2/DMzXT4c++mwz/FcQ36cXFoOKeEE0zJy6eRSztN5Wh0nlyYgl760fic888q/hhsv/TisXngzfPqrF6eW/vCZ74c/eOpuOP0sTi19K/z6p19uPLmUWj5tSRFL35LRZ6qPOrLsSx92rFv6Yl37lG1Zpz5L2Sfr7O+jdHKpDxTdRhsEatgMtMGjT10nl/pEsxxb/pmZLheO/XTY53iuIT9OLi2DkHBiaTl5dHIp5+k8rQ7IJd45f59oiTqYP395hBJ7ft69/yzuOXFq6eIPeb8ZHv/K6+GP/+YH4aNPX5xa+u0nXt2cWvrAn95qJJfaEh/QT916OaZ0Ld+WTNuU7T71LVtaJtuyLmNCXfbJutY7pO3k0iHo+dguCNSwGeiCSx9jnFzqA8XybPhnZrqcOPbTYZ/juYb8OLm0HFLCCaZl5NLJpZyn87Q6fnJp5JNLm7+1tDm19JPw5Dfe2vlbSx++8d3LU0t3NqeW3v/Jbw5CLrVZcilixeqzZCl/feprW7rNOChnKeWQNd3UP7R0culQBH18WwRq2Ay0xaQvfSeX+kKyLDv+mZkuH479dNjneK4hP04uLYOQcGJpOXl0cinn6TytjpNLI5JL+FtLz67fCU/f+mnYnFr6+o/C48+9Hj6+PbV0N8hTS+97/MUscilFhujlldJFn75K00d8sZh07E1ta75NY/rsd3KpTzTdVg4CNWwGcnAYQsfJpSFQnd6mf2amy4FjPx32OZ5ryI8kl958880w5u2EyHIIEc9lf7l0cinn6TytjpNLI5FLR/c/siGKupTTLhH3PhQCTi4NhazbjSFQw2YgNveh5U4uDY3wNPb9MzMN7vDq2E+HfY7nGvLj5FJ/pIATLI5lH2vAyaX9p/PPf+I/BtylXE4ujUQulZJwj6McBJxcKicXtURSw2Zgqlw6uTQV8sP69c/MsPimrDv2KXSm76shP04uOSHSByHiNvpbR04uXT37SyOVGJmTS04ucS14OTICTi6NDLi785MAA64BJ5cGBHdC0zVsoCeEN+nasU/CM3lnDflxcqk/UsAJFseyjzXg5NLFo7+kk0r6y8jJJSeX9Jrw9kgIOLk0EtDuZotADZuB7WRHrji5NDLgI7nzz8xIQBtuHHsDlIJENeTHySUnRPogRNxGf+uodnKp1NNK8qvJySUnl+R68PqICDi5NCLY7mqDQA2bgalS7eTSVMgP69c/M8Pim7Lu2KfQmb6vhvyURi7dvH68/4/aHF8PN8/OwtnqJBxfvxn2iIyb18Mx/yVk6kL/7CysTo7D9Zu7G3/Tx+V4bR+6Jys5fhVO6CMWz6Vv+I/5oh8dX1v9PSyEb++TeZtPvVZyaQ6kEr+VnFxycolrwcuREXByaWTA3Z3/LG7ANZBLLv2H//XvtlHUsDnbTnamFc/RdIlz7KfDPsdzDfkpkVwi8bJHjphkziqcHF0RSBty5mS1JaA0eUPCZ5cwihMPh5JLe3NQ5I8V38WYm+H68UlYZevH59AUg/eXhV2N5FLJP4GzvitALvG+/dobocYb87937972xp6f9+npaXjgwYe295FsoA4FKqPUhs7PzwNuXu957yrom31e1oUA1gvWhlwzqF+7dm1PBjkWql+OwCEI1LAZOASfQ8aOQS7l+jhkHj52FwH/zOziMWbLsR8T7fa+asjP7MmlPcIJpMwV2WSRN7HTQUdHR+qU0sXJo10iqt3JJRA3q5Oj7Ykrkl+Qwd+RIMZ2SJ7VyaZfE23WfHbGKTLK+8oijnLyURO5NKfTSvIbBPvVGgklOefRyCWQSn9793zvhrzLdfHg5QP4qqQt9MurL33aZZnjg76lbu11J5dqXwHjz7+GzcAYqFokjyWTp5QYl5S1yQfs86YtL4dHoE2Oho+mLg+Ofdn5riE/JZJLfJ9muSVYLgkXyCnbP1m0+1M4i4yxxsQ2/SYR1eJncbALGzJe1tFnxYef/12QTjiVdTXXqL4TStuTarE8zkleA7k0V1KJ31hOLo30s7gYsUSySZ9mkm0mK6fElwovWYdMt6nHMtVv9Vkyy1ZKj/o1lk4u1Zj1aedcw2ZgDIQtIsmSSSKJcUlZm3yQWLL80LaX/SPQJkf9e6/bomNfdv5ryE+J5JIkX3ZIgb1TStbJol3CxiJvTMKIf7NJ/KQOvveJqN2TS3j/xx2NGcQPyKJLu7QXO7m0kZO8uiSNNrLL8dZ8djByomn2RNPSyaW5/QTO+pZycmlEcslKQJPs6P5HmlR2+iWRI+tQ0u2dgQ391lhLRpuyT9bZ72XY/JzSfxbnK2FMBGrYDIyBp0XwWDJJJDEuKWuTDyeXiOC4ZZscjRvZ8r059mXnuIb8zJ1c2v8j380/i2tDxpAMuhqzSy4lSaUzxHL1qwvsFa7ui7+n5GTR/H62drUWhol9qeTS3E8ryW8rJ5dGJJd4Sgnll//h3fDs+p3whTtvh7988V/CZ57/UXj8udfDHz37w/DRp78Xfu9z3wm/8+SrwckluVyXVfeTS8vK5xxmU8NmYIw8aCLJIn5AIvGWMTm5JNEov+6fmely5NhPh32O5xryM3ty6azFH/QWP6u7Inkk4XNV599ZOoxcaiYfbHLJ/mPeIDVs/WY/QxMibr+/HCyNXFoSqcTvDSeXKiOXrC8MLgb0xS6rz5JxvOyTdfZ76SeXfA2Mj0ANm4ExUNXkEnxqGYklSSZpWZt8WATWGHOt3UebHNWOVd/zd+z7RrRfezXkp0RyCe/Uezd+Fmb8LG5Daty8Ho45Zu8nZVd/3LuRADHsg1zai4U+DH3bR1uyqK1+f8SGHb/bHxOXJZFLS/gJnPWt4uTSROTSl779b+GZb/0s3Hjxx+HJF94Mn/raP4dPfPmfwsf++vvh95+6G373L74dfuszd1qdXNIkTlNbLwj5BSH7aIcl+3QbcmnDqnOsl04u+RoYH4EaNgNjoKqJJMunJpKgo2Vt8uHkkoXy8LI2ORo+mro8OPZl57uG/JRGLiU38dlkzhUZYp30MQmjnL+dpP+eUXY8cbLIni/0DYJtE2MLskzH6+1Z/D2mJZBLSzytJL+tnFyagFzCT+K++OrPwhdefjt87u/PNj+J+5Ov8Cdx/7j5SdyHVq+ED/7Z+OSSXBysk0RiqeVsy1LqyrrUqb3uP4urfQWMP/8aNgNjoDoGuaR9OLk0Rmb3ffhnZh+TsSSO/VhId/NTQ35qJZf4szeb3Lkip5L9g5JLF3+TSfu3yDKt4+3M/BVKts2ZXFo6qcRvEieXJiCXvrR+Jzzzyr+GGy/9OKxeeDN8+qsXp5b+8Jnvhz946m44/SxOLX0r/PqnX84+uWQROFqm21wELK1+LZNtWacNlrJP1tnvpZ9c8jUwPgI1bAbGQFUTP5ZPfUoJOlqWyof2ESOXtJ4Vi8u6I5DKUXerPjIHAcc+B6XpdGrIT63kEt7bzZs/ecshHlqRSxF/5r805yeXaibI5kgu1UIq8dsI5BLv26+9EWq8Mf979+5tbxwo4X16ehoeePCh7X0kG6hDgcootSH8a2C43/PeVcAf8n5OnFq6+EPeb4bHv/J6+OO/+UH46NMXp5Z++4lXN6eWPvCnt7LIpRh5o+W6zUXA0urXMtmWddpgKftknf1eOrnka2B8BGrYDIyBag6ho4kkxKVlqXxoH04ujZHZfR+pHO1ru6RPBBz7PtHs31YN+ZkVuZRD+LjOLH76VTN51DT3OZFLtZFK/Jbxk0sjn1za/K2lzamln4Qnv/HWzt9a+vCN716eWrqzObX0/k9+M0kugbRJETe6j/pWiQVh6XOhyJJ6LNln2bVk1K+9BBkJ4lESkqhfu3ZtTwY5Pqx+OQKHIFDDZuAQfHLGxkgePVYTSejXslQ+nFzSiE7TTuVomojq8erYl53rGvLj5NK8f0LVRFR4//zyOwdyqVZSid9YTi6NSC7hby09u34nPH3rp2FzaunrPwqPP/d6+Pj21NLdIE8tve/xF5PkEpMYKzX5E9OjfGh9+vHyAgEnl3wljI1ADZuBoTGdilzCvDThFJMNjUFN9v0zM122HfvpsM/xXEN+nFyaH/nghNGyc1YyuVQ7qcTvDSeXRiKXju5/ZEMUdSmZLC+XhYCTS8vK5xxmU8NmYOg85JJLiAMnleSVe3Ip5sPJJYnmOHX/zIyDs+XFsbdQKUdWQ36cXFo2UeFE1PzyWyK55KTS7veSk0sjkUu7sHvLEfC/ueRrYHwEatgMDI1qjPix/HYll2Arl0iy9KxYXNYNAf/MdMOtj1GOfR8oDmejhvw4uTQ/8sEJo2XnrCRyyUkl+/vFySUnl+yV4dLBEfCTS4ND7A4UAjVsBtSUe286udQ7pEUb9M/MdOlx7KfDPsdzDflxcmnZRIUTUfPLbwnkkpNK6W8IJ5ecXEqvEO8dDAEnlwaD1g1HEKhhMxCZem9iJ5d6g3IWhvwzM12aHPvpsM/xXEN+nFyaH/nghNGyczYVuURCmQITNgAAIABJREFUCaVfaQScXHJyKb1CvHcwBJxcGgxaNxxBoIbNQGTqvYm7kkvr+27s/GtxaFs3A5U/d6MeZKjLS+pJudf7QeD2ndv9GHIrrRFw7FtDNuqAGvLj5NKyiQonouaX37HJJZJKoz5cZ+7MySUnl2a+hOcbvpNL883dXCOvYTMwdG7akkvrSxIJceX8QW/qk0hCmxeJJOpADtnP/cJnNzf1vOwPgdtOLvUHZktLjn1LwEZWryE/Ti7Nj3xwwmjZORuLXHJSqfsXCsgl3rdfeyPUeGP+9+7d297Y8/M+PT0NDzz40PY+kg3UoUBllNrQ+fl5wM3rPe9dBX2zz8u6EMB6wdqQawb1a9eu7ckgx0L1yxE4BIEaNgOH4JMzNpdcWl+eVJI2Y+QSSSOp2yQjoST1KEPpVz8I+GemHxy7WHHsu6A23pga8uPk0rKJCiei5pffocklJ5UO/w7BfrVGQknOeTRyCaTS394937shP/Q6OjraM2HJoAS5dWsDlg5ltCPHsM8qLX3KLH3KpP2l1Z1cWlpGy59PDZuBobPQhlzSsRxKLsEeCSTUZSxrccJJ6+k4vJ2PgH9m8rHqW9Ox7xvRfu3VkB8nl+ZHPjhhtOycDUUuOanU3/eDk0sj/SwuRiyRbNKnmWQ7J90gY/SVK+M4Sz/VN5R+yi7jWULp5NISsjivOdSwGRg6I5LQiflaK6KHeoeSS/pEko4FfrVvSUYxDi/zEfDPTD5WfWs69n0j2q+9GvJTLLl083o4PlkFTaSsTo7D9ZtX5MLqZP9/Jh9fvxmod/P6cThZXelf2VuFk+Pr4eaZ7DNkiGPvf1ifhNXlOPq5sivtXdQRA977rRuxyrH78YqYVidB62PsFQZX2NAOSmuM9mnFBpk1ts18tn6sfFrzWZ3s47TN081w/fgK+63tnRzu4z83vSHIJRBLfvWHQC659PDDDwfe8tQPZSgplzLW2adL9svx0Gkr13bbtEc5udT1dNLR/Y9kZRsPOX3lyjjO0k/1DaWfsst4llA6ubSELM5rDjVsBobOiCZ0tL91hFiC3iHkkiaWYC8WixWDNV7H7u19BPwzs4/JWBLHfiyku/mpIT9lkUurcNJAwsTIHJIpJBKotyuP2z/aEBiCyCFhAVJkS26AuADBIYmiK0KHvnW5G0Oa/NjXFTHFyBiScCBmLmOlHZQWQSRjpK6Udarr+Exi7hI7xKz1iflOuQonnN8GeyeX8DTLfTb5aaVuz/6mUTnkkkX8kACSJA71WMo+q6712GbJMWyz1HK2u5ajkUs8pYTyy//wbnh2/U74wp23w1+++C/hM8//KDz+3Ovhj579Yfjo098Lv/e574TfefLV0De5hAUB8sa6U4vFInwsGW1YfZbM0k/pUX8JpZNLS8jivOaQ+4U7r1mNG22M0EEU6wSxhP6u5FKMGGobS8zOuAjOy5t/ZqbLl2M/HfY5nmvIT1nkUpp4AeFB0kiTH5ogoZ6W63G7bUHkkOAwyaUrgoN+du3szgMx4L3fuvWpqv14RUwGGbPrH8TXBdlFOyj7JpdS82nytYOTMZ+dfuRgR8dPLvG51fRsclKJSA1T5pBLmrQhycOS/WyzpDxWaj22WXIc2yy1nO2uZZXkkl5OTYSO1W/JaNfqs2SWfkqP+ksonVxaQhbnNYemL9x5zWaaaNsSOjLKNuQSx6UIoVQsGL+O/EyOtr1sRsA/M80YDaXh2A+FbD92a8hPieTS1c+8QMhckSV4d2ZbkxAYI4kaki4kWaS+JkeuCBFB5PRMLsnYZCy6rmPbzJknp3aIFp6iuiK6YEtiB5+wdzW/XdKLvk2fJMO2p4auxkI/dz7wsWtfxLs3nysfF7FpMkm3tf4y2of+LM5/AtfP8z9l5RBySZM5JH9Y6n7d1npss6Q+2yy1nO2u5STk0pe+/W/hmW/9LNx48cfhyRfeDJ/62j+HT3z5n8LH/vr74fefuht+9y++HX7rM3eyTi6RjGHJhF980Vz83wDIZDtV53iWtMtSymmHMpTUY8k+3aYubVglxy6xdHJpiVkte041bAaGzkCM0Fk3nFpCXGOTS8RCx5YirDjGywsE/DMz3Upw7KfDPsdzDfkpjVzaEBGS0Nj8tOqKkCBpRGLkorz8uZsYp0mWrT5+Oib0Ln7mxp+25ZJL8hQSxxrEhvX3g0jaqJJkzT5xI2IS9i4Io32yhfjQDsomcmmLDQm1hnKTIxX/dn9DIuzSxkZX4i1PgjWRS3v9+/NtG/sc9A8hl5xYynmyH66TSy6B2OFtkTiS+KEeS0sfMjlGttvKY/Zz5aOTS/hJ3Bdf/Vn4wstvh8/9/dnmJ3F/8hX+JO4fNz+J+9DqlfDBPzucXDp8ibQji+CPJBJLxqDblMsxui51llZ3cmlpGS1/PkNtBkCa1HKNSS41kUBWLJrAYl7Wivxqss1xtZdDfWZqxzVn/o59DkrT6dSQn7mQS9e3Py3bJ3NIpKxO9kko9m1JhSZy6ZI02RIy5t8N2veztZ9BzGxtG7p78Z7tkkt6LMmkC/9X5AvtoNRjtrEKsmpLDkVII5Jf27GCPIravzxJtTsWMV7mUPjfs4E+RVRdEIFX2OtYltLuQi75z+DG/Z7IJZckURMjf6jT1N+kFxsfk9Ne13J0culL63fCM6/8a7jx0o/D6oU3w6e/enFq6Q+f+X74g6fuhtPP4tTSt8Kvf/rlxpNLmrCRbVmXyyr2kJQ6rGsbsi3rXfWtcZZd6i2p7EIu4WXOb8egtDUAQqO0mPqIR5I3tGfJ1vfdyJq/JH5oDyVsyjbqIH+0TLetWGI+1kaMOT60T2/788fXgK+BWtZAaeQSCAJ56kj/DG6XTDkLZ/IkDOqXp2SoR5JFEg+Q4T2c9xWxIYgcg/iRNlinH7atUvujX5RXvi9OPu3HK2LaO8lz8TeJtiexBHFGOyi1DyvGLJkgg+QcrPqWUBIxbXxsyLpLgsiaD39Gt0csAZ8r8iwr3swclmYLn8lHP/hoeOyxx8Ln/+rz4fm/ez68dOul6PsSiKVanlclzBP7dBArsTtG1kiSR9Zz9KWOHss2S+qyzVLL2e5ajkouPSdOLV38Ie83w+NfeT388d/8IHz06YtTS7/9xKubU0sf+NNbvZNLeMjFLqtPy2Rb1mlTy2Rb1qnPUvbJOvuXWHYhl5aIg89pPATwxdP3JcmMvm1PbU+SN4zFkq3VqSDq6lJjhXxoeyB8ck8V6bHwp33IGKw4c31JOzXVh/jM1ITfIXN17A9Bb/ixNeSnRHIptdnfJXPwc7jdkywkU6hHkmXfpiBttiSEJbsgfWhP24nJtZ7ZNsgVxIs9ws5NosXQh90rMu4KC86beJj+t/OWNoRv+XM2odtkS/fvzukqxt0/1k2cj9TPFi/kFzbrIZc+8pGPhCeeeCLcunUrvPXWW+Hdd9/deeDx2eQ/g9uBZbQGiJW2pAxJHpZN42N6Ws42S9plm6WWs921HJVc2vytpc2ppZ+EJ7/x1s7fWvrwje9enlq6szm19P5PfjNJLsVIGMpZytVkydiv+3Rb6+l+3c7Rx5imm3aWVjq5tLSMlj8ffuH2GWmKzOjTzxS2LPJGy9aZxBLi11ghH9JeW6JHjiU+2gflKGOxtvUrbS69PsRnZumY9TU/x74vJIexU0N+yiSX4iSPJi5ibZI+JFk2eg0nb05Wcb+0F/OXku+SK7t7glaniiLkkuWb80bZ5APklKVjjwXBszsHucex7FjxbWQt5nNhw8klPun8Z3BEYpoyh1yKkTpaTnJHy3W7SU/rs80yNp7ytuVo5BL+1tKz63fC07d+Gjanlr7+o/D4c6+Hj29PLd0N8tTS+x5/MUkuNS2ZFNkjH3asN9nT/TH7Wo/ttvoct9TSyaWlZrbceQ2xGUiRGeUikReZRd5o2bpHcikvqistHQt6mvIRi9cJpitcZW2Iz4y07/U4Ao59HJsSemrIT1XkUuPpm+HIpe3PxBpjkCd1VL0FGTMcuaRikvNpEZ+TS3Ec8ZmMnVwiqVTDs6mE74BYDDnkEsgaEDu8Sd6wLUurjzLa0W2OP0Qux7atj0IuHd3/yIYo6lLGkufyeSPg5NK88zfH6If4wm0iM+aIk4wZBI68JKGzbkEswYbGCoSOtCf95NStsdqHtpOK2QkmjVbY/K2GfalLxkBgiOfVGHHX4qOG/BRLLiVO/eecjuFJI5Is0dMzkhyRfzx7Rx752dhljE3xIAb+T+69kj95U/7MeFuQN5w3yqb44Ovqp3XiVFLbn8W1iM/JpXbk0s//f/cH+RO4Gp5NJX/P5JJLbQkbSx8kkiWfWjYKuVTyIvDYpkHAyaVpcK/Za+oLF6RE09WFzGiyWXo/5iwvicG6JbkEO8AZJA5u5kP7kP6a6npsE7kEe6m4nWDaRZw52pV6awwEHPsxUO7uo4b8lEkuxTfeJumSQ8y4TnDs5rGu5Mmln/t//rvwX37sf4j+zaXuTzcfeQgCY5JLU5NIMf9OLh2ygnxsZwScXOoMnQ/siEBqM+Dkkg2qJm8OJZckeZPKhx1Ns/RQcgkeZIzNHpetMUSOlo1Yf7Nz7PvDcghLNeTHyaV5EA5ODNWTJ3wm/7P/9F+H//x//28a/6D3EM89t9mMgJNLb2z+tbx79+4F3tjz8z49PQ0PPPjQ9j6SDdShQGWUNIIS7fPz883dnArXqA0Brg+5ZlC/du3azjpiPz6sfjkChyCQ2gw4uWQjq8klaEG27nBqSZM2qXzY0TRLc8glWGmKX8fa7HmZGkPkaJlI9T8rx75/TPu0WEN+nFyqh7RwgmoeuZYnl5r+tbg+n3duKx8BJ5ecXMpfLa7ZKwJOLvUKpxvLQCC1GXByyQbQIpeguW5BLoGosciaVD7saGzpG589CrwluUQZSzk6J34rZmmjhnpfOaoBq77n6Nj3jWi/9mrIj5NL8yAcnBiqJ09OLvX7HB/CGsgl3rGfjS1djvnzcAhK7Pl5+8mlIVad29wg4OSSL4SxEUhtBmonl+TP3WReLHJp3ZJYkvZkPZUPqcc6SaJUmSKXUuOG7GP8cyzb5miOcyw1Zse+1MxcxFVDfpxcqoe0cIJqHrl2cqns7wVE5yeX/ORS+at0oRE6ubTQxBY8rdRmYMnkUte5IZWHkEtNJ39S+eAyyiF9qItSkktSnmNnTB0ZW8n1nByVHP+cY3Psy85eDflxcmkehIMTQ/Xkycmlsr8XEJ2TS04ulb9KFxqhk0sLTWzB00ptBroSMDEyoyQYus4Nc9Dk0jrz1FITsQTbqXzEiJ4mXNvmo8/5WLHF5mHJrfFTy1I5mjq2pft37MvOcA35cXKpHtLCCap55NrJpbK/FxCdk0tOLpW/ShcaoZNLC01swdNKbQa6EjBtyYwp4Ok6N8QqyaV1BrEEUimHWIJtnQ+LcIGszRXLRwyDnDnRf5u5cYxVxuZJuTVmKpnO0VRx1OjXsS876zXkx8mleRAOTgzVkycnl8r+XkB0Ti45uVT+Kl1ohE4uLTSxBU8rthmIERJ6KiBaeLMvdyz1+ywl8ZOyGyNW5BjOS9tke51JLEmbTXXmg6SKLpvGW/2xfKQwyJmb9JVLnskxTfU+5t7ko0s/c9RlrI85DAHH/jD8hh5dQ36cXKqHtHCCah65dnJp6Cf74fadXHJy6fBV5BY6IeDkUifYfNABCMQ2AzFCQruyCJjcsdpWH20SP022UsQKx1pzQx99rBvIpVzCRZMous14upaxfKQwaJqbFUtfp5i07b7x0PbbtmOfmbZ2XL89Ao59e8zGHFFDfpxcmgfh4MRQPXlycmnMp3w3X04uObnUbeX4qIMRcHLpYAjdQEsEYpuBGCGhzVsETO5YbauPNomfJlspYoVjrbmxb30gsaQJE6tNX4eWsXykMGiaXyqmIUimIfFJzcXqi31mLF2X9YuAY98vnn1bqyE/Ti7VQ1o4QTWPXDu5ZD/JH330UbtjAqmTS04uTbDs3CUQcHLJ18HYCMQ2AzFCQsdnETC5Y7WtPtoWuWTJUsQK47Dmhr71AcSSRZJAxiuWD/Z3Ka18WDJtu2meWl+3xyCZtM8x2kPkaIy4l+DDsS87izXkpzhyaXUSjo6Odu/j6+HmGYiBm+H68UlYbepXRMHN68fh+PrNsEeerE4MOWwo+8Lfnp0O8axO4vaPTlb7car57M3D+6vCzMml3e8FkEolEUuIzsklJ5d2V6m3RkPAyaXRoHZHlwjENgM55ANMWARM7tghkmARSZYMMTZd1tzWHYkli1Sy/MfyYenmyqx8WDJtr2muWj/Wzv15YGy8Jdd4WjpDyYbI0VCxLs2uY192RmvIT3Hk0h6RsgonW0KmD3LpipTaI3FMMkrrN8ezZ5dzAlG1nYu26+0obsSvkrJ2colkEssSvyVALvG+/dobocYb87937972xp6f9+npaXjgwYe295FsoA4FKqPUhs7PzwNuvxwBjQDWC9aGXDOoX7t2bU8GORaqX47AIQhgM2CRKDHyQRM1TWPX993YnPRBCV3ZpuyQ+PXYtvHJ8TljEXPqsoiUNkTI7Tu3U+Y79Vm5tGSW8ab5WmMsmYWLpddG1gbXNnabdIfIUZNP779AwLEveyXUkJ/iyaUdwidOLu2ddro8jbR3EilFUOz4ipA9Ozp2PH5yKYJdCnvv257OqolcIoEky7K/FS6iw361RkJJztnJpTms1AXG6OTSApNa+JSwGWgiiOQUcgiYGHGhx8IuZOtLAkr66VrXPtDmTZu58XEcbSLO1KUJlC7kx1CbM8xZXjEMpA7qTXPW+rpN7CDX+Gjdrm2Jc1cbbcYNlaM2MdSq69iXnfka8lM2uaTJG92+IDHa/SwuQXzsEEeWnvav2xdjVifH4fpNa7zL/HRS8xpYKrkkCSTWy/4GiEfn5JL/LC6+OrxnUAScXBoUXjduIIDNgCZRoGaRD5aelK0FSaTJDKknw4CclxxPWdtS2sNYy681N+pKf3IsYktdmjiRhAfquRfyMcSl8xHDwPLdNHdrDGU6Hxon6h1adsW7i9+hctQlltrGOPZlZ7yG/BRNLu2RPTaZA3Ip++SS9TeUUn9zSZ6oyYzHyaVmAsVJpjhGSyCXSB7JsuynfbvonFxycqndinHt3hBwcqk3KN1QJgLYDEgShcMs8sHSs2SwocmMmB7k+lo3EDlaX7a1PcuvNTfYyBkrfbEuCZNDSY6xNmcxDDgnWfaZD9iVeEk/h9YPxT7X/1g5yo2nJj3Hvuxs15CfYsklkEDbP+TNjbhNLkmiInqKSZJEsfoeeUS/Z+GsRTzJn8Ud7f9Bchm/1wXmsTwtXD43ckkSSKyX/WQ/PDonl5xcOnwVuYVOCDi51Ak2H3QAAtgM5BIwlh5ca1IGskPIJYxfdySYdCxWzBaxYulxbrFYQJJIoqQPcmOszZmFAeYbu2IYxPQp1/mgXOJGWV+lzENfNqWdsXIkfXr9AgHHvuyVUEN+SiSXNieR9oglkA6KXGo4hSRPM52smkkL+LX0suMxSI+DyC7DnpNPzXmcO0Ylk0skj2RZ9lN8mOicXHJyaZiV5VYbEXByqREiV+gZAWwGLGLFIh8svfXlH+rWYR1KLsEebFsXSR2WUkeTGVbMuXODXW2PvjQ50hehMdbmzMKAc7PKWC4sXcos7NEH3xo/jumr7CsfVjxj5cjyXbvMsS97BdSQn9LIpc2pn+i/qKbIpZ7JF4tcOjQeJ5eWTwb1TWaVQi5JAon1sp/Y40Xn5JKTS+OtNve0g4CTSztweGMEBLAZsEiAGPmgyZZ1hFzSoVs+LJkeB/u4SEhYpIQkmWR8kEsfHGvNTeoxBmtu0hf1+iQykI8xLguDJr/MRZMe+y1MpV/mg/p9lzIvqPd1jZWjvuJdkh3Hvuxs1pCf0sil9EbdJpcsUsi00/NJp6FPUplz6JlQcx/lkV9TkEskj2RZ9tN52uicXHJyadoVWLF3J5cqTv5EU8dmoIkEkKFBl9f6kviRMvbp0vJhyTAOBAQvkjlSxj5dQhc2OYb9Mj70SYKDOiilnp6btslxksCg7JByrM1ZDAMrdmJPTCwdS2blV/sFrkNeMj99EUxj5WhIXOZq27EvO3M15Kcqcql3YsYmu5ywKY+wmVNO+iSXJFmUqpf9JC4vOieXnFwqb1VWEpGTS5UkuqBpYjNgkQAIkaSCDDdFwEg9XY/5kPY4Bn41mWPFQn1ZWva0TBIc0g/11vfd2PqHLEaASOJCxnBIfczNWS6mUg/Y5F7AjjfHSOwpi+HL/j5KmatDSaYxc9TH3Jdkw7EvO5s15Gcp5JL8+0o7dfNvN/VFfji5NCfSZi6xdiWXLPKo7CfsfKMDucT79mtvhBpvzP/evXvbG3t+3qenp+GBBx/a3keygToUqIxSGzo/Pw+4/XIENAJYL1gbcs2gfu3atT0Z5FiofjkChyCAzQAJAJTykqQC5dRZtyAZMDbmg/ZoH0SD9isJiSa/2h590z5KaY9y+MVYlJLssOxhjCQraKOPcszNmcY5Fr/Wa8oB7QA73pTFsGf/kKXM2SEE05g5GhKPOdp27MvOWg35mRe51Bcp5HbmQrTUGGcOueRE0rTfHdiv1kgoyTk7uTTtGqzWu5NL1aZ+soljM0ACQBMpmlRAkNRZ90wuSVJH+9WEBHzH/DM+CaiWaXvQhT2tJ23IuiQppLyP+u2R/uYSYtU4W/HHsLJ0tQx48mafZQ99ktCj7lClzF8XkmnMHA2FwVztOvZlZ66G/Di55ERTjQROyXPW5NL73//+8Bu/8RtBEko1PJtK/nZwcsl/Flfy+lx0bE4udU9vLjHQ3cMyR+ILlwSAxtAiH6CzbkksAbmYD8g1saD9xggJrUc/OlPWvGgTc+F8tJ62cygpoe1ZbeRjrMvCT/smTlqXmGl92bZyHrOHcXodSFt913Uu25BMY+ao73nP3Z5jX3YGa8iPk0tOLpVMtNQYGz6Tv/zLvxx+5Vd+Jbz3ve8Nb731Vnj33Xd3HpY1PJt2JlxYw8klJ5cKW5L1hOPkUvdcNxED3S0veyS+cC0SALPWhAJk0F13IJc4VqIJMkHnzSIfLBnjQywyHm0PfYyZujF7eqyMVZMRsq/P+u2ZkEuYs8Qdbb1egCdvYhTDnv1jEkzwqfPKNuOxyjFzZPmvWebYl539GvLj5JKTSzUSOCXPWZ9ccnKpvO8JJ5ecXCpvVVYSkZNL3ROdIga6W13+SGwGSABoDDVZADS0ThuEOBYEAkkEymjHIh8sGfRlfOtLEgn2cKONG1eOD/rXJckGlrq/7zbyMdYl8Yv5jGFPfeJs6TEXEn9Lj7ZYcm2wPUbJ/OrS8p3KkZyrNRayHAxiY2uXp7CvHZsS5l9DfpxccnKpZKKlxticXCrh6Z+OwcklJ5fSK8R7B0PAyaXu0OZs6rpbX+5IbAYsEiA240Nwxtgm4sDaeFsyxAe5vuBjrU5W6Zhj9rStHKJBjzm0PebmLIafnkOOnoUpcOcNm8iLpaf9od20Tqwxfcma8p7KkV5rVky5GFhja5elsO+KjbW+u9qqfdwQ+SkNUyeXnFyqkcApec5OLpX2lNyPx8klJ5f2V4VLRkHAyaXuMOds6rpbX+5IbAZIADRhuG7xR68txJrsY0xs421tAC2Z5UPLYj4YcxO5QL0hyjE3Z7n45ehJTLFOuFaAPW60edEe9SjX5ZQEE2KJrYPbidNleq3pOaEtsbL65yD7+U/8x6Dv3Lj1uFjbspfC3tLPkXE95ui6ThqBIfKT9jh+r5NLTi6VTLTUGJuTS+M/B9t6dHLJyaW2a8b1e0LAyaXuQOZs6rpbX+5IbAZIADRhuBYEQVtEQBQ02YfN2Mbb2gBaMsuHlsV8wH+MUGg73676Y27OcvHTesCTN+dpYUodC3+OQ4l1FVtbpRFMWB+pHOm5ynmybmHFvqnLGNGj5VacWifWtsZaMmt8CnvLRo5Mr++cMa5jIzBEfmxP00mdXHJyqUYCp+Q5O7k03fMw17OTS04u5a4V1+sZASeXugOas6nrbn25I7EZiJEActbrA4kl2MrJUWzjrTeAMT3Lh5bFxkpiSc59zPqYmzONaSxHWs9aLxamll4KS6wxa52BYCqNZLLmYc3XkllYWfb6lFlEjSXr0+cQtqyYLVkb33p9txnrursIjPn82vU8XsvJJSeXSiZaaozNyaXxnn9dPYFc4n37tTdCjTfmf+/eve2NPT/v09PT8MCDD23vI9lAHQpURqkNnZ+fB9x+OQIaAawXrA25ZlC/du3angxyLFS/LhDAJs6v9ghgM2BtgKUla8Mv+1N1SQrk5sja7OXKUrHIPtqThBLrUm/s+pSbs6Z1QCwsPeDJO6XHvlSJ9WatObmWUuOH7OMaYSl9WbhYMuLENSht9FE/lGzpI4ahbOR+PjQGqXisPFiylA3vu0AgNz9zxsvJJSeXaiRwSp6zk0vlP1GxX62RUJJzdnKp/HW6yAidXOqeVmzi/GqPADYD1gZYWrI2+rI/VtdkQG6OrI1driwWi5bDHgkCWWq9sdtTbs6a1gGxsPSAJ++UHvt0aeXXWnd6TWk7Y7TlemEdfi1cLBlxsubM+DU50qZNG0ssu34+UvghD7Jf5gdyv/IR6JqffA/Tazq55ORSyURLjbE5uTT9c7EpAieX/GdxTWvE+wdCwMml7sBiEycvuUGQcq/vIoDNgLUBppa1wWdfqrRIAJ2j2PjUpluOydWTY0gGYCzrsn/q+pSbs9Q6kLhYerHP26E5t9aftbZkfEPXmSOuH5QgISQuJCssmcSKeroceg5ztU/s+4xfP0dkfuBH5wZtv2wEhsiP7Wk6aZHk0s3r4fjoKBxd3sfXbwaSDKuT43D9piCElO5mzMkqrn/Gsatwcnw93Ny2ITdklv2jk7C6HLcXz9lZuHn9eBs758BSzoVzaqvPcV4yl8sqnVya7nmY6zmXXHr44YfO8LfHAAAgAElEQVQDb3nqhzKUOXKpg3rb8TF9bbdN208u5a4W1+sVASeXusOpN7F6g9Dd8vJGSqywGZAbYD3bdYe/tTTW5l9vCnXsui3JgLZjta2h2lNuzlLrQM7X0ot93uRakzZ0PZUPrEG9DsdaYyAS5NwsogEyrC0LF0sm7REHS8Y+L68Q6PvzYeFuya4iuKhZ60Dr1NjuOz8lYlgcubQhc67Imw3hI4imoyNFLu2QQ2fhbHUSTlarcLIdI/Wl/Iq82hA/G6IpQi7tkFA3w/VjOVbavyA5QBadrHogPFYnwSKjnFTqAVu9bgpqO7lU4pNyN6YccskijkgMSRKHeizZp9sxOfVYar2YnHpdSyeXdteEt0ZCwMml7kDrTWzOBqG7t3mPlFhhM2BtgDFDvaHPmfVYm/6cWKgjSSXUcWF9lHhNvTmTayOGT2y9dMU097Oq1+Mha80iBywZ1wpjRNvKkSaXuM4srGhL4mXJYvjXLLewPwQPC3dLluMjtn5yxi5Fp+/8lIhLceSSRagImXVS6IpsuRmun+yeRkrra5Iil1y6Ir8s+23JJT+5pPNQd9vJpRKflLsx5ZBLmrQhycOS/Wyz1HK2Wcb02sppr2vp5NLumvDWSAg4udQdaL0p7rpB6B7BfEZKrLAZsDbA64JPLLVB2iKW2owfW3fqzZlcG6m5W3r4zHW5Yp9Vy55elzkEU9tNv56bji+WI/k54rqTMmKj7UFuyajv5RUCMeyvNNK1ptxidJ+5sNaelqUjnlfvofmZw2yXQy7hRNHlKaKdn7LZJ4v4MzWUV6eD+iOXpP2duvjJHkmxtmQUx3m5TBLKyaXyn5xOLvnfXCp/lS40QieXuic2Z9PQ3fqyRkqssBmwNsDrmZNL3NyznEsGp96cybWRwszSw6a8yxXbzFv2LBkIJt56445220vPTccXy5H8HHHdoYRctrU9xGfJ2sZdg34M+9y5N+V2ilxwzebOoWS9Q/NT8twYW3HkUpefxW3G7JNIIF/2ThatTsLRDsEjSKnY31xq+bO4tqRP6uTS0Y7vZZIpbfFaur6TS3w6lVvmkks4TcSbJ4QOPWHUdnxMn/F0Lf3kUrnrc9GRObnUPb05m4bu1pczUm6AMStuBiR+ayeWJks48zFVAHIdpGKw9CziJ2WDfTFiRdrjBhwy1q2SJFPOiSb616Wem44vliOM4y1tQhYjlyDH5037kON1Xcen+/toj+HDirPJbwx7y5Yl0/Yt3C2ZZatvmbWetaxvn33bOzQ/fcczhL3iyCX87ZvEyaNdsujy7x+1IWCayCX9R8R3YuHfWor8LA62t3/ribp2GfubTCCark5SOZm0dCLJmp+TS0M86fq1mUsuSeKGJA9L9rHNUsvZZhnTayunva6lk0v9rim3lolAF3IJL3N+X5y+kTjIDYKU117H5oq3xAIytNf33Wi9nrCRl7amrMtN/JRxzNU310GX+PGZ6zqOn1eM54YaMtZpF7J15hol0cSxuaXGgLGhTNng50qOR6yyzfGwJdeq9IEx1LNKbU+OtfS7yLSPLja6jLH8NuEe82PZsmTa/hB4xmJsK+fnQZZtbcxNv7R8FEkuJf648i65RPJF/5FtSejsn2jSJ4WuyBzjZ3GJWEAM2PEwroayBzLKIidc1oB7Q06nxg+fyUc/+Gh47LHHwuf/6vPh+b97Prx066Xk9+jcnoNzjhdbYBArsTtG1pD8YUk9tllqOdssY3pt5bTXtXRyKZMMcbV+EehCLvUbwXytYdMgL/lCKuW114ETb2CBLyxcxG/d8tTSISdE+s6F3Kz3bXsse8zHWP7G9CM3xLqOzytliCn2+YUcV5t1SpIpd678LFBfxxLLET9XKBEfY9T2aBcl16z0QVms1PbkWGn7kLr2cYitNmMtv8w57MSwt3xYtiyZtA87Q+BpxdeXjJ8bln3Z7WKnTX5y7ZeWjzLJJZBFV6eD5Ga/LZkT17eIJEt2QVTE7MTlkuC6rO/8HG/eBIjMidf7zaWfXMp9mk6nB2KlLSlD8oclx7PNUsvZZhnTayunva6lk0vTrb+qPTu51C392DDwpoXSXkgZ19QlceImi5sBtLkZbhNjCeSS3oS3ib80XeajtLi6xMPNLsuUjdwNPvW6rtWc9crPBuPVzxLmSOtBv+vnSPrQ61m34YMy+JRjGfOhpTW3Q23mjNd+9dyIfRdbsM1bjocPeWmfsm8O9ZzP21DzaJOf3BhKy8fcyCWbyMg8udRwUuhk1Z5csuJZncg/En5FPNg/eUvFbtuxfLrsCue5Y+HkUu7TdDq9HHKpLdkT09fkT0yvrVzbbdt2cmm69Ve1ZyeXuqWfGwa5MSnthbTbzIYZJXGSm4H1DE8tcZPNchjExrMq8zGe13499bG5jX1+IefVdr1yXOokU86zBDmy9GBffrboL6eMzVeORdzSL9e8HEsZSzm+Tb3rPHJ9yHlwjCWTc4Ne7ufDsmXJ6FuW2qfsm1Odn0OWY8Sem582sZSWj+WQS/s/f2tPMkxBLiVIkdWJ//2lwn/C1n6NJfJ9OVcnl9o8UafRzSGXQNaA8OEtyRvKLEKIfVpft2N6beTSZtu6k0vTrL3qvTq51G0JWJuG0l5Iu81smFHAixc3A+uZE0ucz9xL5mNO8+DmlWUfscc+v5DzSq1Zucapr0uSTLLMeZYgR5Ye4snxa8Uh56vjYRvjpF8SSHIsZbrUPpvaXebRZFP2y3lQbsnk3KCX+/mwbFky+pal9in75lzn55PlEHPJzU8b36Xlo1xyyfhZmf5j21vioa/TPylyqU08+FtMhn7bn8U5uRSGIG9Kt+nkUpsn6jS6ueRSW8LG0tcElKUzhczJpWnWXvVenVzqtgSsTUNpL6TdZnb4KOCgL+DFi5sBbIxzL2x2p7wO3ThPGXuTb+ajSW/Kfm5OWQ4Vi7V2tSy2buUaT8Wn7clnCdc5dHjDFnIk9RAD48jxS7KIJWzSvhWPjF/7bRorPyvSTqoufaT0DumzfFgyjQuwz7ksW5Ysx9ZSdYb4/Obmpw2meg20GTuEbpnkUvPpjtIJAo/Pc9h1DTi5NMSTrl+bY5JLUxBHOT6dXOp3Tbm1TAScXMoESqlZm4bSXkhVyKM19WYVjoEXL2wGuDGmrKnkprtJb4h+uVlGfWnXEJuzvjAaYjOaik2vXeszHVu7co238aGfJVjr2i9zBF3tP+VXkkk6Ju2D/dqejg/+m8bqz0zT51f7YCx9lpYPS6bnRuybYrFsWbImOzX083PN8pA55+anjQ+9BtqMHULXySUnQbqSID5umLXj5NIQT7p+bTq59MbmX8u7d+9e4I09P+/T09PwwIMPbe8j2UAdClRGSSMo0T4/P9/c/abNrS0BAa4PuWZQv3bt2s46Yj8+rDVe2CTIK7ZpwEtp7ZeFgcQPmwFsUHOvpo1prp22enqD3Hb8XPSH2JwdMnduOFGOfem1G9tk6vUbex5Y8Wsf0JGfD7SlX/jirfX0WJJJLC3/lEkflGl7bHN+1MsZy88PdFmXJW3FfMj+Puqcg8ZQt/Xccj8fln1L1sdclmZDfubbfu5z89MGM70G2owdQtfJpWEIAideHNeua8DJpSGedP3adHLJyaV+V5Rby0bAyaU8qPQGJLZpwEtpzVfOSzk2yrnXFMSS3ACznhvvHPWG2Jx1wYEbzC5j+xqjP7+p9SzXcex5oOOK2dPPF9hmLJIoknqUy1L7S7VzY7HmljsW/qHLz1GslD6kTmxsal6xPulD6khMGS/nh3bu58Oyb8mkb1lHzq1b6tRSb/MsyM1PG+yYf5QlXE4uOQnSlQTxccOsHSeXSngypmNwcsnJpfQK8d7BEHByKQ9avQGJbRpKeRnNm1X/Wjkv5dhA5V5jk0tyY4t6DdcQm7Mc3LiBZJkzZmyd2Hrm55xkQOx5oJ8bMXtyXvx80Af6kCN8FmCPZJIc06VuxWLNw5LJsYwXMej5QibnwTj150z6YJ/0kZKxj7ZjpfQhdXTM0i/0gH3OZdm3ZJYtiaHuT/Vp3aW1+Wxgac0vNz/WWMqa1gD1piqdXBqGIHDixXHtugacXJrqaZjvF+QS75y/T7REHcyfvzxCiT0/b/9ZXP5acs2WCDi5lAeYfvmMbRqsjVSeh2Vo6Y2ZnhU2SrmbgTGJJW5QWeq4l9zOzUcfGHCTiHIOV2w968957HmgnxuYsx4rccDng5fUY44se9RvW1pzy52HHou4cVvxyXnEYpR+SZ5pHxgrZfys5pbShxwDuWxLH/BJ7GOxUy7tU4YS8thF3GL9lEPPrxDk84P13Pyk8NM50msgNbZL36OPPhra3E4uOQnSlQTxccOsHSeXujz5xh3jJ5f85NK4K869bRFwcmkLRbKiXz5jGwm8lNZ8Nb2UY5OUsxkYg1iSG0pZry1/Ofk4FBNuBA+1M/b42HrWn3PreWDJEL8eyznhsyEvqccc6eeQ1G9bt+YWi1n7tcbCP/RS84jFaPm1fFgy2JSf31hd+ojpQC59aL1Y/Jw7fUg9yKxL42TpUNZGl2NqKflsYdl23syZzJNcA23s5RJGtAk/OZeTS8MQBE68OK5d14CTSzlPrml1nFxycmnaFVixdyeX8pIvXzwxwnohhTz3ZTHP6zy1Yhhwg3Q742cmQ5JLesPI9jzRPjzqnHx09dJ1w9fVX9/jYptMvcbl8wDrHLeUybj0WOpLHV1njvRzSOu1aVtzi8Ws/TaN5ZwsPStGy68cy+eBlFl2UjLLh6UvffDZkCppI2ZfYwd94KMvntjSJfWsMeyrueRngxi0feZYeZNrAHbbkkaMpamEn5zLySUnQbqSID5umLXj5FLOk2taHSeXnFyadgVW7N3Jpbzk6w2C9UIKS7kvi7l6edGVpRWbGzdHejOgo+dGUssPacc2h4fYXMrYpnx0mWfbDV4XH2OMwVrmLf3pNW49D6SMax82OBYyKZf2dZ050s8hrdemzXkxHoyVMUtb2m/uWEtP2mXd8qvH4rmgZRyfU1o+rHHaB7GHPPYcgVzal3qQy3aqbsVDsgl9uevFsrNUGfOj58dnEEvdz7bMG2QgkuQaQHuoC35yLieXhiEInHhxXLuuASeXcp5c0+o4ueTk0rQrsGLvTi7lJR8voPLSL6Tsy31ZzNWj3TmV1tzkpii2GeAc+ySXYhs5+vIy/2/K5GDVtJHLsVGSDtYybxmXXuPW80DL8BnAjbHy8yDtxur8zOjnUEw/R855ybnomGN2csdKPc7fshnzK2PDOGnPspOSxXzoMdoHsdexYJx8vkj7Wi7bbeuMjyRT27XD8UstmZ+m+fHZJEsQRzJvJJL0Gmiy3aW/jQ8nl5wE6UqC+Lhh1o6TS12eeuOOcXLJyaVxV5x72yLg5NIWimQFL6Dyki+kUm5tQGQ/67l61C+h1DG3wUBuiFKbgUOIpaZNWwkYlhhDKh+58XLDlqs/F73YBjDns9Dm89GEB3Okn0NN41L91txiMVt2NAbQ0fFZPvAssG6M1XKMh4yXtEeyhX1NZe7cpA/YvH3ndhapFbPPecn4rOdc7vMLYyUm0m6NdeRHXyCJcm48t2Te0Mal14C230e7jQ8nl4YhCJx4cVy7rgEnl/p4Cg5rw8klJ5eGXWFuPYqAk0tRaHY68AIqL/lCKuV4YUxd2BTgbtJL2ZiqT8eci4HeCFmbAczJ2nA1zbVpQ4Z+v9IIxPKRHnXRu1RSqWnuOZ+F3M9Hky/0M0f6OZQzNqWj55HS1X3WWB0fdHjr8bqtx8p+PENw05b0TZKp6fkRy4f0g7r2AeyljLHoUtqXfXJejFX7jLVjz7emucbsLVFukUht5inzhnF4psl88xmnZW18QFeuA7SlvSZbxZFLq5NwdHSk7uNw/eZZOLt5PRwfXw83zwziAn0nq7C7ob8Zrh+fhNWO/iqc7NmX/rT+Wbh5/VjFc6V/fP2m8nkZmzGPk5UR99lZWJ1c2dub+96c9m20ja+t/i6m+/69v19MnFxqempN3+/kkpNL06/CSiNwcikv8frFEKMsGV4Y9QUZNxvoa/NSqW0N0bZitvxoPf1SzjFaD3OX123j/zSjv82GKbbpkn68nodALB+p0dxwpXSW2md9fmOfhdxnRBNWzJFlr2nsUP36c275sbCCnjUPS6ZtxuxRL0XewD5v6FNXl9IH+vD8kjL60iVtW/OgDz0mtx173kl5rq256FmkkSXjZ6PrvKy8WfnWMj4Dm0rGpdeFtkc9qyyOXNohgi427auTPsklSQSAfDoKRw0EDsgYkxhanQSLXNqQN3sk2AWpZdox5rwhbEBQNcQGvWh8MbsxeWQ+Th7JNTN83ckl60lVlszJJSeXylqRFUXj5FJesvWLIUZZMrww8optSuRLJXSmvmTMqVi0nvVSrsdb87M2A9h85VxyM8V6zjjXiSNg5SOmzY1UrL8Gufz8cr6xz0LTM4Ljm0rmyLLXNHbK/jZY5cQp7eHZgtu6SObIUuYo9ryBPekDtqErZbGx0j7H0b8VY1cZn3s5ZVcfY4+zSKPcGPjZyNXXejpv6Jf5pr4lY58uocsLz0zpg89QaQ+y1FUquSQJkxxyySZ0rJNLF+TARv/o6II02pwy2j+xRFJFxkLZpjTJGPi8JMM0iWOerurn5FIb0opz3zsldXRkkmU7c9Zz8rZ9cu0AXJxcSj2xyugDucT79mtvhBpvzP/evXvbG3t+3qenp+GBBx/a3keygToUqIxSGzo/Pw+4/XIENAJYL1gbcs2gfu3atT0Z5FioS7rkS2BqXng5zLlgT2565Askx2tZbINE/aHLHAx0zIhJvjBbMcbmpTcDsc2atqk3U7rf290Q0PmwrHBDZPXVJrM+C8DAekZYspzPm8aUObLsad2S2hZWTc+NVPyWPTxneKfGWn45jqU1/rb6WRx0SBrJUtrPfaZZ/trIEDcu/WxMtdvYH0L3ECLJigf5OeSSeaMda51ZMurrErryyvHBZ6wsaaN8ckmQNdGfxeFU0HE4PtbkyD65tCVWLk8EoX1x+ujq53L6NNJ2jPFzOq17dibi1QRDlFyKkFF6fKSdis86+QT9NmSUk0vDn1aSGDu5xKdTuSX2qzUSSnLOTi6Vuz4XHdkh5BJemOZ+6ZfA2Hxy56rtWS+kloybhJj/IeU6ZsuXFbP1wsyxqfnIzUDOJkxvlOjDy34QkPnQFrnR0fKa29ZnAXhYzwhL1gW7VI662BtrjIVV6rnRFJdlD2Mgx4XnDm7rkn5TenossI/5lbrSvpQPXZfzJdkFn/q5mWr3EaNFGlmyPnxJG8jPIVcsb1xTtB1bAxivLz3W8hGzJ23x+Vs+uSQ29iBnLgmeK1IHZA5JJf3Ts31ySW7iUb8il4SfCImTrW+ehNKxXfnbnsxK+NVxH9JOklF7P+e7ivMQnz42H0cnl+STqsy6k0v+s7gyV2YFUTm5tPt/GGMpt14gtS5e8vVLpfUCaclgS24StO0h2zpmy5cVs/XCzLGpucjNQIpcsjZDtO9lfwjIfNAqNzVse3mFgPVZQK/1jLBkV5bya1aO8kdPp2lhlXpuNEVq2cMYyOWF5w/8oOTd1S+wj/mVPrvalza61DE/fZFkYsl+65kqZdRrKscgjZpiYD/yc8gVy5teU3oNyHXFOkvoso7YLB/aXmoORZFLxh/Bvvrp1klY7Z1cuiCWdk/hSJkil5L2d/+o9sZmW31JDu2NjZ9OSv5B76P4z/XO9nzszuEKu8uf/8n4LuttyTUnifJJoq5YObmUemKV0efkkpNLZazECqNwcml3UxJbAng5TF14kcTV9EJKHb5Yapu0o+VDtnXMli/GK3WtF2aMbZrD7cvNQBtiyYrJZf0gwHzAmpNKzZhanwWMsp4RlqzZw76GzNF+b7kSC6vYcyNnFpY9jJPPJdrR2Hf1C+xjfukLZVf70oauW/PSOmivDYJJ6pFkkiX7JblkkUaWjGNLKA/9bMTyBuyBK2+5Boi3NVbqAR/o5uilsCyKXDLIj50N+h65NPxGf8d/U3w99A9K9vRARo2NR43+nFxKPbHK6HNyycmlMlZihVHURC7hBU9fOS/v1ouhtMMXTSljXb9oQm7JqJ+yRZ2+SwuDHKwsXHLiv33ndvRfhpMbHdT9Gh4B5AMXiCW/mhGIfX6tz4wla/awr8Ec7feULbGwsp4bubOw7GFszjOsq19gH/Mr4+5qX9rQdWteWoftdQPBRD2WFmmkn799tum3bdmEwaGfDStvFpbWGrDGWnqYM3RxwTZIPqknST/IZRv1Iskl8w9ln4WzKLl09feS5Gmdi7p98sc8LWT+y2wXJ6H27V6cErr6eV4/RFdXcil/Pv3EWSPpM9acnVxq+yQfX9/JJSeXxl917nGDgJNLzSeXrBdIuXysF1H2yxfIlIx9KFP2pF5fdcSoL74IS7nWk7gg5ty4bytyKbaBkb69PhwCflqpHbbWZxoWrM+MJWvn7UIbn5k5XhZW8rnRdk6WPdjQzybINPZd/QL7HL9d7ccwiPmM6fP5a5FGlkzaIZlBWeyZ3FUObDgWPnLnlqMX+2xYY2M5ghwXMCSOxIJlrj2tR2xlCZtSj35RQs42fc+KXIqeDAK5ZJFI6mdxl+NjBE5MHiUVNAnW9mRQW/3I/EEsWSSXPZ9xybIodpG5uP7ZhvD9yEc+Ep544olw69at8NZbb4V3332XH9lNeXum39s7k5hxw8klJ5dmvHznHbqTS/vEis5o7IUUengJbLrwsigv+VIp5azn2KRuH6WODzb5si3ta70ULnKcruMlGxc3G7rU+t4eBgGSSv4C1A7f2OfX+sy0sxzXnmuOLKy6PjeAjmXPkkFX56OrX2Af8wE5r672OV6XMZ9Sr4k0kro5dRIgObptdICNfM7nzA32Y3oS99hnwxobyxHk64bv8hx7wE/q8bvOwkrqsV/LEBNkTi5dneSxyZir/j3iQ5NLExEm7cil8uezh/NEuE4Vh59c4lOr3NLJJSeXyl2dC4/MyaWrzUEq1Xj51FfTyyj18XKoL8hSL/K5trXdLm0rPmu+Wi/2ot4Ug9xksN40xvv7RUD+BO62/9+1VuDic8BbDrQ+M7L/kPpcc0ScrGdHVzy0rVwfXZ9XwD7mQ8bS1X4MB+0zRSTJOPr47kiRIrF4U3J+Nvi8l3OjzMJP6tG+liE/uWMtPdhlfPRhldovMJL2iJnWs2xBZunFZKWSS7GfoR2ZJ5SG/FncPMiYXn4WVwhZNhWpU4pfJ5diT7Zy5E4uOblUzmqsLJKaySXrRS6Wfv3y2eYFHn7khZdQKUObMtZlKccOUZex0L6eL+RaDxhYerRhldxIsLR0XDYcAjytJD1gc+ZXPgL4HPDOH3WY5tJy1Pa5kUKPudDPJ+0Dbd4pe7ovhb30Sdvar7aX0waRJOeFduqScUAPz+ZDL3wH9XVpTOTc+F0g8aPM0rNkcixjlnqUWXrASsdHfZb8fqZNiY01FnpdLtpHSQxQFkkuVXZSpRRSw+NIEIkjrkknl7o84cYdA3KJ9+3X3gg13pj/vXv3tjf2/LxPT0/DAw8+tL2PZAN1KFAZpTZ0fn4ecPvlCGgEsF6wNuSaQf3atWt7MsixUHlZL1XsK7HU8coXORmv1kOflnV5eSdhBHvWy6eW0Yd8kZVx9lXXfjFX3tKH1st5Ked4+aKMul/jImCRSozgtpNLhCKrxOeAd9aAHpSWliP9PD0EIuZCP5+0Dz7TtLzJdwp76bOr/diJpNi8rHhlHOjHs7mPS35nHWJPY27NTeLH7wupl5LpsYhVjpWxMxZgRJwogx7nLEs5Pqeu8xEbwzmxlDFThtLJpTIIBSd2PA9cA04uxZ5q5cixX62RUJJzdnKpnPVYVSROLl1sFGXS5YumlLPOF1K2c0pNEFkvn5aMvviim+MrpiNfwKWO9pujx7hSWMmXY1m/7WSGhH/wuvwJnOXM82Ghkpbpz0xa+/DepeUo9dxoixZywVuO1T5izzU5xqrHsKdProUc+zEiyfKr7Vs6lDEGtlGueyKYYAvfP5YP6S9V17mw5hbDT/vVY5EfOZbfNVqP8UFXYsPvVpbUO7RkHG3KWMxOLjmpQVLDyzLWgpNLhz4hhx/v5JL/LG74VeYeTAScXGpHLsmXUhNQQ4iXVn3pF2b0WzLtz7Klbcfa8gVc6mi/MT2OkTFBV1+xl2nGftvJJQ3ZIO3UaSXp0PMh0cir689M3qjuWkvLkfXc6IoOcsGbNqxnmCWjfqqMYU+fXAvafhsiyfKv7Vs6lDEGtlmuOxJMVn4sH5aMvmWp7Vlz0/hxvPahxyI/ciy/f6QeZSihK9us01/bkuO7ltKfjFnKnVwqg1BwYsfzwDXg5JJ8QpVZd3LJyaUyV2YFUTm5lE8utX1RT/2f0KYXZrn0tF/aJVkjdVN1+QIu9XQsMT2OkfFAF1fsxZpjZKzYDPg1HAK5pBIj8HwQifxSf2byR3bTXFqO+NzohsbuKGtDbj3DLNmuJbsVw177lfab/kaS7WlXqu2zV6+9mB7014pc0mNpU5dWfjCW3z3U72rPilniR/sotQ89FvmRYzFnzhu6se+moeVyDrl1PTeOc3LJSQ2SGl6WsRacXOLTqdzSySUnl8pdnQuPzMmlXXJJvqTq1POFVct1W7+A6360m16Y5ZiUX/qS5I0cK+uxuelYYnqwpWOJvaBLvzq2204uSXh6rTf9BM5y5vmwUEnL9GcmrX1479JyhGdMX5e1IbeeYZYsJ4YU9vDNE0pd7adisNaZllnzlzbXlwRTk54co/Ojx/J7R8cCG1pm4aLtYZzWQ9z6pn2ORxs6eizkuBgL470U7xWx77Fc+Z7BAwSMWZpwcqkMQsGJHc8D14CTS/IJVWbdySUnl8pcmRVE5eRSHrnEF/SmJaGJlJi+foHky7KWc3yO/6YX6KYXcPqK6aEfccReuDlelhYet51ckhD1UnOAzxQAACAASURBVG97Wkk69XxINPLqsc9p3uj2WkvLEZ4xfV3Ws9N6hlmynBgs7Eko6XXQ57wQm7Zvyaz5Q0/Gsr7vxsYWdZvmLcfSpzVWx0cdKbdwb9JDvNal54H2bXVyid+DKOHH+g6ybJcsc3LJSQ2SGl6WsRacXCr5iXkRm5NLTi6Vv0oXGmEt5FKXF1ymPPaiy36WbV5i5cs3xlsv27SLMjcG6PLlWo5H/RAMML4NqcQ4dAxoYzPgVz8IHEIqMQLPB5Eot1xajjR5cQjy1rPTetbBRxe/JJJkyXj1c5zyoUprrpbMmr+lZ8WZO1ba43eflNG2tMfvMakHGW6px7FWKcfK7zqMX+rl5FIZhIITO54HrgEnl8p/2jq55ORS+at0oREulVzSL5rWi6t8SWV6pR5fetmXKvlyndKRffAtLysW2c+XcilrqvPFm6WcmxyrY0Ef8WtLKNFuCo/bTi4RpoPKLj+Bsxx6PixUypJ5jtrng8+wNiMlgcR6Cnvr2dnGX1td63vCklnPekvP8t9mrJw/v2ekbC2II/qCzIpF+qUtq9RjmZ8u+WZMpZdOLjmpQVLDyzLWgpNLpT81Q3Byycml8lfpQiN0cinvZ3Gp9KeIlNQ42adfmGUf63gpP+SSL+/SjtwMUA5di1hif6pswoObgZQN74sj0MdpJWnd8yHRKLPuOeo/LySPZGl5SWFvPTstG33JrO8JS2Y96y09Ky5rLPSsucZkmhSCTcpoi/FQHvOrY+Q4+mZ+MH6p15Tk0p07d4LfjoGvgYs1QHLPyaXyn7Ygl3jffu2NUOON+d+7d297Y8/P+/T0NDzw4EPb+0g2UIcClVFqQ+fn5wG3X46ARgDrBWtDrhnUr127tieDHAuVl36Z023qTVHqWNDmzXj0SyrleizlsbKJTImNk/KcWNY9kkt8oUcMfEmXZBIwYFvG2VTPwYKbgSZb3r+LQN+kEq17PohEuaXn6LDcSAKJ9VyLpWHP5zXjt747+F0nv8uk3jrxXWKNhS/tV8tgE7elx1hR4jtCxiL7cup6bGn5yZlDW50pySVupr0s48SM56GMPDi51PYpNr4+9qs1Ekpyzk4ujb/u3GMIG1KyD3Ip9kI6FcjypRoxxOLTL8J4OdZjU3PIIVNS49mnX5gp17Egvq6XhQFf9EkksaTfXH+wk4tFDZuBrjmyxg1FKtGX54NIlFt6jtrlhgQSy3ajd7VLw15/Z1nfHdazXuutL8kgOVvI5FjqxErYZB/t6Pgol6WORfY11fXY2xX8zNrJpTIIBSd2PA9cA04uNT2pp+93csl/Fjf9Kqw0gr5OLskX0hKgJDnCWHLiw0syLj2WNnSZS6bocVZbvzBLkof1ptKyK2USA2kLvtmmPnSJB2Wxsi0ONWwGYli1kQ9NKjEWzweRKLf0HOXlpg8ySXsqDXs8r5su+aynrv6OoXx9STKhxGWNpa4urVgsmTWO8ei+pjbH0U9p+WmKv0u/k0tOapDU8LKMteDkUpcn2bhjcsmlhx9+OPDmqR+2ZYk+2WadY3TJfpSyr61cjm1b95NL464593aJgJNLF0DwxRotvFw3XW0JlSZ78oWZRA9KxCLbqENXy3LactOg9REf5sR5NWFAXeo3zU/217AZkPNtWx+LVGJcng8iUW7pObJzQzKJpa11mLQ07EmqpGYln/XUk98xlKHU9qyxUn/qup5HafkZAh8nl8ogFJzY8TxwDTi5NMSTrl+bOeSSRfxYBA71WFo6Uqb12GZJXbZZajnbXUsnl/pdU24tE4ElkkttX47X6qdmOcRKJrzZavKFmcQPBlux6M0A9DgmVebiAsIIupJA0vXsiRmKNWwGjGk3isYmlRiQ54NIlFt6jkIggSTLMTJWGvbW81/jEHvW67Hye4c2YmPZP3WpYy4tP0Pg4+SSkxokNbwsYy04uTTEk65fm04u+c/i+l1Rbi0bgbmTS9aLsCWLAbJWxBL0MD52dTmpE7MFOckg+cIMGS8rFuhacXNMrMzFBbYtvzG7beU1bAbaYDIVqcQYPR9EotyyxhxJEgn1qa4lYy+/d4hv7vcE9acul5wfYuvkUhmEghM7ngeuASeX+HQqt8whl/SJIH2CCP1SJut6rGxrPbZZUpdtllrOdtfSTy6Vuz4XHVlXckm/gOo2QcPL65CX5deSWTGsDWIJehhvXX0SSySVWOa+5Ft6VqyWLAcXYhLDwLLbVlbDZiAHk6lJJcbo+SAS5ZY15YikUinZWDL21vdJzvdEKblBHEvOD3F2cslJDZIaXpaxFpxc4tOp3LItuaQJHhI6Uo66vKmjSzkGfWyzpD7bLLWc7a6lk0vlrs9FR7ZEcgkJS5Eja+NfyZFJtsb2RSyRTJIlfOe+5Es9zKPN1bRpaGuvjW+pW8NmQM5X10shlRhX7fkgDiWXS84RySSWpeVhydjL7xPi3vQ9Qb1SyiXnhxg7uVQGoeDEjueBa8DJJT6dyi3bkEua3JFkjuyTdejoNsdpOdsstV5MTr2upZNL5a7PRUfWhVzCy5x8AbXakOHGyyvrLC0Z+5pKPVbHwfGQsy7L9X03TLnU0WNBLMn+rnVJKKEu7ciXfMqtuWm9dcZ8UvbYh7KNLTnO6xdrvQkHkkpNet6fh6fjNE+cSCKx9DxOl0f9fYJcWN87nqPpcgTsiyWXbl4PxyerwA33plydhOPrN3dlZ2fh5vXjcHR0ZN/aRoO+ZV/GsDqx/ByH6zdBjtwM149PwupsnygxxxmxSV/b+urEmNulT+B0fD3clD4t/a1OPMatP2nL63vrbWic8Jl89IOPhsceeyx8/q8+H57/u+fDS7de2nmv9+fmdM9NbNxBrMRuSdZoYie3D3qxsVrONkv6YJullrPdtXRyadEUTrmT60IuYTbyBdRqc8Z4eZWXfJmV8ty6tqfjoB3I9bXOPOnDsSCV+jixpEklHRfaFi7W3Cy9NvOiTR1Drg09rksbX7g1XSSVSp1zbfkoNQ+puJaQI5JJqXmW2LcE7FO45n6npmxM2bf0/ADbssilVTiJkEQb0idBLp2s9gmdGAkAMqqNvmnHIr8i5BL8WaRVTH7hD1jYRBX6VycJcmmPEFqFEyeXRieJzHWzl5v9desnl6Z86uf5BrHSRMpoUkfrd+3X49hmST9ss9RytruWTi7lrRXX6hmBpZJLGqZ1JrGEcSBg+iCVYCuHWIKeRRqRCELJy9LLnZtlj3ZzbVD/kLKGzQDwKZ1UYg5ryQfnO8dyjjkimcRyjrgj5jli3wZrTS5hrPzOaWNrCt2l5weYlkUuiY22Rd4kyKXYySWLREqddLL0LZJgY+OSsNm1t08IxUikmHzjz5gr9Bmfk0tirWQQNlYOh5K98MIL4Vd/9VfDD37wg06ElpNLUzzt2/kcglzKJYFiem3lXUkljnNyqd2ace2eEBiSXLKIEEvWZipdX4TXilziqaRY2SYmSzeXVOJYCxeLDLL0YMPChbZZWvaAi8aG+kOVS98MzIVUYn6Xng/Oc87lHHJEEonlnPGWsc8Bexlv23rOd0dbm2PqLz0/wHIp5BJJlxzCQJI0Ofr7OjhVdBxOTvSJpPhPztr9LM62cxU3+hMnl/xncZ1Inf08dyewfvM3f7MzweTk0phP+W6+csklED7yJjGDUpNBlFE/pUsdbaOtXPpoW3dyqdva8VEHItAXuYQw9P/ttIgQS9ZmCtaLsPar7a3vu7E5iSSJJK3TZ7stsQTfFi4WGWTpWTJrPtIeMME9xbXUzcDcSCXmfqn54PyWUJaco6WRSXq9lIy9jrXGdg35KZVcApFypH8WJkgT+TOzK9Iljwy4sG397aSjcNT0d5Bwouro6PIEEUieI/GTN5sUAmkBnzpm2d4hNoxTS7SxR6JdxoOTW1t7kfEXPuIx7sRQ2GmgOcbWlWBycqn8b5sccqktWRPT1wRSTG9suZNL5a/TRUY4Jbm07kButCWXSCiNlTxJLLX1qecmySDasogkKZOYatLNske7Y5ZL2gyQUEI512tJ+ZhrDpriLi1HJJRQLv0qDful4912fjXkp0hyaUOYHIfjY0X2REiTJFm0/VtDecRTmsS4IJN2CR4pU8SNIMNiP9ujXNrc/uQNBE/SxklYASs9xwhOTi71sQba2fi1X/u18L73va/VSSonl9o+qcfXH5NcGps0yvXn5NL46849hhCmJJeQgHXLEzSagIENTaJANjapBJ+HEEsYr+dmkUGSSMIYXFoGTHFJXCCz7G0UR/7PEjYDJJVGhm4Qd0vIxyDAFGS0lByRVCoImsFDKQX7wSc6Uwc15Kc4cumSTLk4hXNB3ByRPEmSJhmb/iRRs3uSSZI9acIpw2+bU0Agi5pOT0l7Ti61Im7GzOWf//mfh1/6pV8K+BtMbfw6uVT+F4aTS29s/rW8e/fuBd7Y8/M+PT0NDzz40PY+kg3UoUBllDSCEu3z8/PNXf5S8AjHRoDrQ64Z1K9du7azjtiPDysvSV5AptsW6aFltLXOPMWE8frSfkEs4cq1qe11aR9KLFk+LTLIws+SYe4Yj1LioLGy/A4tuz3Tfy2OhNKcTylZuZ1rPqy5LFU2VY5IJrFcKr6peU2FfSom77tCoIb8lEUuXfxrcZrY2fy9IhAuh5JLkpSx6rn2kyTV/h/0BrGQ+zeXdk4tyRhjsUXIJZ6I2i0RmzpdJX14vRUJlCKMuhJLsOnk0tUzuNSak0tOLpW6Nhcf11jk0vqSPLKIEIAMOXSoR5lOAPRS11KIJczxEHKJ41NYTdU3t80ASaWp8Bra79zyMTQeJdofK0ckkViWiMXYMY2F/djzWoq/GvJTFrnUcApIEyxJkid+Ein1M7rt3y3qRLTYxI3+e0skJfblq3DCU1rav5677s9u2zEyJi8b1mAGzjip1OXEErF3cqn8bxAnl5xcKn+VLjTCQ8ilJkgsIsmSwY4kjdaXJJOUUYfjLd8gljjW6h9KxlNLfds/hFyyxvYdX1d7c9kMLJ1UYv7mkg/GW2M5dI6cTIqvqqGxj3v2nhwEasjPrMmljI0+N+yyBKmjT0fJ/u51m7jZJ5EuCAwtT8bl5FJvp4q65zefeHr11Vc7x+vkUs7TeVodkEu8c/9G0dL0MH/+8ggl9vy8/Wdx067PRXsvkVwi4G3IJRJLHDtWORSxxPj1z9hIrlnYcAxKJ5ckGu3qtZBKRKWGzRnnOtdyiByRUELpVxyBIbCPe/OetgjUkJ9ayaXdn4uJU06xk0NZRJZNLoHMaP5ZXOLUEnwnT2nZP8WzSZR4jLZ+PqHi4/vBysmltk/q8fX95JKfXBp/1bnHDQJDkktwsFZ/SymXHMFY6GI8bVhj0cefwo2dUhJLKIe6nFwaCtl9u7WRSkTg9kz/Bhbjr6HsM0cklWrArY859ol9H/G4jV0EasjPrMilLIKnnw2+EyWO41RrwMml3edwiS0nl5xcKnFdVhHTkOTSWhFLBFSfuoG8SQZbuKnH9pKJJeCSSy4RW5Z+colINJe1kkpE5raTS4Si2PLQHJFQ8lNK7VN8KPbtPfqINgjUkB8nl5xEmYpEcb/22nNyqc1TehpdJ5ecXJpm5bnX7b8mKH+TiXrOvxbXBN/6AHLJOqUEf5DT7tKJJczXyaWmVda9v3ZSicjVsDnjXOdads0RSaW5zruEuLtiX0LsNcRQQ36cXLI3+E58OC5TrQEnl8r/dnFyycml8lfpQiMc6uTSOkIsAUaePpKQalmKXMK4GoglzNPJJblK+qk7qbSLYw2bs90Zz6/VJkcklPyUUj95boN9Px7dShsEasiPk0tOokxForhfe+05udTmKT2NrpNLTi5Ns/Lc6yAnl9YJYgmQayLJkqXIpVqIJeDi5FJ/H1InlWwsa9ic2TOfjzQnRySV5jOreUSag/08ZrLMKGvIj5NL9gbfiQ/HZao14ORS+d8nTi45uVT+Kl1ohEOcXFr3QC4B7hwSaqy0jPHHu625OLlkodJO5qRSGq8aNmdpBMrvjeWIhJKfUhouhzHsh/PoltsgUEN+nFxyEmUqEsX92mvPyaU2T+lpdJ1ccnJpmpXnXns/ubRuIJYAeS5ppPVqOrEUW5qxE11aH6QUb903dXvMzQCIJb/SCIyZj3Qk3htDQOeIpFJM3+X9IaCx78+yW+oDgRry4+SSvcF34sNxmWoNOLnUx9N7WBtOLjm5NOwKc+tRBPo+ubTuQC7FCBOSSyCVpiCW5Gkl1Eu4Yljp2Egs6ZNPWg/to6OrW/ZDLi+pp+vQ0/pyLOtyHGUcy74ceUyHNnhaiW2U8orJpQ7rOWOlPdY5XpbSFvWkDLqWXOtIm4fWa9icHYrR1OORIxJKfkpp3Gz452NcvNt6qyE/Ti45iTIVieJ+7bXn5FLbJ/X4+iCXeN9+7Y1Q4435y3+wC3t+3qenp+GBBx/a3keygToUqIxSGzo/Pw+4/XIENAJYL1gbcs10/dfi1hnEEvyTNGIsMcIE8ilIJcRVIrFE7IgX8dMliIg25JIez3aK0LD6LBltoWQ/NwNss6Qu2yy1nG2WUo+kEvqkXLZj8v+fvTcGsSbZ8vyuJ620ICRDsBoZMhbkylAhZq3epb3mg4UBOXKumDFU3jrafhJrrChEWbu0NCCQdg0ZsrSXNfoNsscT9DPK6Ee14PMeApUh0TO17hYpzr31v/fkuScyIzMjMiIz/heyIyPixImI/4mK+vLXkbfgT6djtrYebcfKbT3ySD0/tg42S1PEY6kfts+jAKBSHu/0OqYAfz7GFCpb30J8CJf8B3yCD+pSag0QLpXd92N658klnlyKWSe0yaBA7XApw5RHXWqwNGq8sgHAkqTeRwCEXDFwCbZeKr6lPPTx6rwy3R71eBhAHqm2lXtbbvOwR7l9BQ7l1i5UDjudjtnaerT1ynWZvpc2yCP1/Ng62CxNEY+lftg+nQIASjilxBil03aqJ2o/VbF17VuIT0m49Msvv3S8qAHXwGUNAGYRLq27z8/pjXCJcGnOumGbBAqkgktfI08tyZA9MGLL5MSSLUsw3VEXNYMlaCe6eNoIfMAltjGvxEEQD1x4ZXPt0U5SPAzAP1JtI/e23OZhL+UWLA21t35sXvvFPVJra/Nev6G2KNdtrL+xvPYx9x7xmNue7dIpAKhkPTJGVpH18tR+Pa3n9NRCfErCJTxMM+UpIa6B2xogXJqzW6/bhnCJcGndFcfergrUBpf09yt5AOU68MQ3GirJfa0fgCWrjUAIfcn414BLuk8LQkIaysOAtg350Dbiy+bxCtzU9taPzWPcXrkts3lvnKEyrx/rbywPH0vSFh7OluiTuy2AEk4pef0xRp4q65RR+3V0nttLC/EhXLo91BNwUIsa1gDh0twde712hEuES+utNvbUUyAFXPo64dRSr3OVEVjC71dSggzcjoElAIlYuAR7pOja5m25rbd52NvU2oXyoXLxp08qheymlo+NU+pDPnVba+O1g721nZqHnyVpCw9nS/TJ1RZQKcY/YxSjUh4bap9H11ReW4gP4RKBSg1AhWO4rUPCpVQ7eD4/hEuES/lWFz0PKlATXBocaKZKfWIpUxfJ3Wq4JDBiziWDQjs9QF0m994H5UhhY/Mo16nY2IcB2w55pGgveZxWQpmXoh1S2CCP1JYjj9TaSbktG8t7bVL7h7+5qY3HXD9sN64AgNLQKSXPC2PkqbJOGbVfR+e5vbQQH8Kl20M9AQe1qGENEC7N3bHXa0e4RLi03mpjTz0FaoBLJb5fSUOlml+D6wXrM6PhkhQJ4LCX126ozEIS+LVtrJ3O63vbTvuzDwO2HfJIpa1AJZ33/KMMdkhjy2GH1LaXcls2lvfahMq88hj/0m7Jx8ZjiS+29RUAVPJrx0sZo3GNcllQ+1zKpvHbQnwIlwhUagAqHMNtHRIupdm/c3ohXCJcyrm+6HtAgaVw6evCV+JKvAq3ZbAkobRwScoEQuhrIORulYUY8GmNrZ3O63vbTvuzDwO2HfJI8Qoc8ta3LUceKeyRR2rLkdfpmO3Uevi27ULl2k7fwz5FauORwid9dB2A0tRTSp52jJGnyjpl1H4dnef20kJ8CJduD/UEHNSihjVAuDR3x16vHeES4dJ6q4099RQoCZfWBktbh0q9wDkZgQ+4nOq7Ith6qRhLuf7YPOpQjhTlNpV6e8FGl6MMp5VQh3JJpUx/YLO0XPuUe+sPZehvzN5rb31YX8jbtjZv+56bb+HhbK42c9oBKs1pG2rDGIWUyV9O7fNrvKSHFuJDuESgUgNQ4Rhu65BwacmuvU5bgUu4Xv/wa9fiJfN/e3u7XvLMj+vp6an75tvvrtdBZ+ReDGAsqXX08fHRycUPFbAKyHqRtaHXjNw/Pj7elUm5LFR8vm7o1NLewRJiAjCB/JJ0KsyItR97GBj7XqXYfpbMXbed29/cdrpv3Kf0BZ9Ix+IBO6ZhBQCUUpxS8nphjDxV1imj9uvoPLeXFuJDuHR7qCfgoBY1rAHCpbk79nrt5Hm1RaCk50y4tN56Y09KgVJwaa1TS61AJRVS97SNri99P/QwgFfgSo8xRf85gVCK8cHHUDxgw9RXAFDJr01Xyhil03KqJ2o/VbF17VuIT3Vw6XTsDodD/3p47l7eBXy8dM8Px+50vr+BkJfnh+7h+aW7AwOno18u7V+eu4fjqd8mYC/+78aEMVofZmx3Y2J9X3PqcacH4dK6+/yc3giX+FrcnHXDNgkUWAKX5nZPsDRXuX208x4Gxk4r7WPmdc7Ci0edIy0/KsAkpGuNiDFaS+n7fqj9vSY1lbQQn+rg0h1sOHXHK8BZCpdO3RFQyKRnODUAl46nG8waBUYCrg4CwWS8fVAm/ZyOh26SvztNJoyFbe/gzWj8CmtGuFTTbwF/LIRLhEv+ymBpdgXWhkslwFJ2EdnBJAX0wwCh0iTpshjreGTpYMNOAZGQlpoKY1RK+a6j9uW0j+m5hfhUD5d6wCcMl0Ini9wTTQIPEp1cuodEeoz6XgOhULm24X3tECjX+AiXYnbnsjaES4RLZVdgw72vBZcEKhEsNbzQ1NTxMLCnV+DU9DZ3i3hsbuAZB1waJtmpMUZWkfXy1H49ref01EJ86oZLFsLY/AXArPFa3D1ECsCfCBh2hhI9u4CvwidocsET+h2ON+HSnN163TaES4RL66449nZVYA24VAIqyXct8VOnAjytVFdcWng4i1EcQEnS2j6MUbmIUPty2sf03EJ8qoZLdwAmDJemnly6fI+S+f4m9X1P+sST2MbCpdNR+/THe4Erp+54/S6pYdhAGNOWPoRLMbtzWRvCJcKlsiuw4d5zwyWCpYYXl5k6oFILDwNm6lVnW48HoFLNQWo9RiVjQ+1Lqj/edwvxqRYuCei5gy9DsOYCIIKnmPQpoPN3Ij10D/J9SNfvc3rv3u9g1s1nCF71x2iBkYy3/51LN0g1PhdCpbagEuJNuDS+N5e2IFwiXCq9BpvtPydcKgGWmg1kxRMHVMIQW3gYwFy3kLYYDwClGk8peWumxRh5OpQoo/YlVI/vs4X41AiXzqeK7sCSgAYDZNRJoyD8+fzi7ivU+WxzOZn0CX/QVwAu4aF/PPXgkj7J1Icl/VNO/brxvmi/V40Il+L36FKWhEuES6XWXvP95oJLBEvNL63OQiUo0sLDAOa6hbSleAAqbSEueowtxUjPu4Z7al9DFMJjaCE+tcEl+UtqvdNE+sSRhUu9uhjYcvlrcVfQ9Nn+2ueqcMmAsslziZkvbbYIoAiXwntyLTUCl3C9/uHXrsVL5v/29na95Jkf19PTU/fNt99dr4POyL0YwFhS6+jj46OTix8qYBWQ9SJrQ68ZuX98fLwrk3JZqGOfNcCSfKeSvsbGxPr1FAhBJYyghYcBzHULaQvx2CpUwvppIUaYa20pta8tIv3xtBCf2uDSMAzwgcyU70Qa9G/h0uSTUXZ8Nq9hjz3lpOt4PxinnYM4wqX+PlxjTp5XWwRKes6ESzWuzAbGtEW4pKESv7i7nkU6BpUw0hYeBjDXLaR7jsfWoRLWz55jhDnWmlL7WiNzGVcL8SFcUiDHwqUZEKMPugbgUoK+WgYwe5474VLdvxdkdIRLfC2u/lW60xGmhku5Ty1psLTTkGxuWrFQCRNr4WEAc91Cusd47AUqYf3sMUaYW+0pta87Qi3EZy9wKfidS/g+pRhQlAT4xJ1IOh0fuucXBbZixkebbs9QCXMjXKr794KMLhYuffnypcOFUz/I69SrQ5mXem3Fbmq55zu2jCeX6l+nuxxhSrhEsLTLJRKc1FSoBEctPAxgrltI9xSPvUElrJ89xQhz2kpK7euOVAvx2RZc2giMkdfpjqcuBLzkO54uXyi+kfkQaq0KtQiX6v69IKOLgUsCejSoQR6prpN7W27zsLflyCO1dqFy2M1NCZfqX6e7HGEquJQTLOnTSnwNrvwynAuVMPIWHgYw1y2ke4jHXqES1s8eYoS5bC2l9nVHrIX4EC4R8ODEDNM61gLhUt2/F2R0hEt8La7+VbrTEdYOlwiW6ll4S6ESZtLCwwDmuoV0q/EAUJJ075+txmgPcaH2dUexhfgQLtUBFAh2GAesAcKlun8vyOhi4JI9EYQTREhD9SifamftkUc65hf1sSlPLtW/Tnc5whRwKdepJQ2Wdin+RiaVCiphui08DGCuW0i3Fg9ApS1om2qMW4tRqnnX4Ifa1xCF8BhaiA/hEqEGoAbTOtYC4VJ4T66lZipc0oBH7vUFmKNtpMzmx+ysPfJIQ+1RPjUlXKplNTY2jqVwKQdY0lCJr8GVW5CpoRJm0sLDAOa6hXQr8WgRKmH9bCVGGO+eUmpfdzRbiA/hUh1AgWCHccAaIFyq+/eCjG4KXBqDO6hHCshj86Fy2CG1dqFy2M1NCZfqX6e7HOEcuCT/mMMlcAn3KVILllL4pI9bvGK0AFSKsaXNNG2p13S9zsBsRQAAIABJREFUAJWo3XTtqBk14xrY/hogXCLUANRgWsdakJ/J73/zfffDDz90P/72x+6n3/3U/fz7n5M+D3Hvnr93Ay4JXPEuDWss2NF1uIcNUluOPNKQ3dRy+JubEi7tEt3UP6k5cAmzSnlqyUIl9MF0PQUAlXL3KL8w+alHgVrjAahUj1LlRlJrjMopsl7P1H49ref01EJ8CJfqAAoEO4wD1gBPLs3ZrddtI2BlDMpY2BOyhx1S2Nl8qBx2SK1dqBx2c1PCpXXXHHv7VGAJXFoqogVKyC/1y/bTFFgLKmFULTwMYK5bSGuLB6HS/aqpLUb3I9xvCbWvO7YtxIdwiVADUINpHWuBcKnu3wsyuiVwKQR7QuUW/oTsppZbv1PzhEv1r9NdjrAEXAJEsukuBa54UmtDJUjRwsMA5rqFtJZ4ECqFV0stMQqPcL811L7u2LYQH8KlOoACwQ7jgDVAuFT37wUZXSxcEuCjLwAcr0zqhsrRdswOPmLstc3Ue8Kl+tfpLke4NlwiUCq/jEpBJcy8hYcBzHULael4ECqNr5LSMRof4X4tqH3dsW0hPoRLhBqAGkzrWAuES3X/XpDRxcClqbAmZC+wKFRXspxwqf51ussRrgWXCJXKL5/SUAkKtPAwgLluIS0VD0Kl+NVRKkbxI9yvJbWvO7YtxIdwqQ6gQLDDOGANEC7V/XtBRrcmXCoJkIb6Jlyqf53ucoRrwCWCpbJLpxaoBBVaeBjAXLeQrh0PQqXpq2LtGE0f4X5bUPu6Y9tCfKqFSy/P3cPx1OGB+5yejt3D80u/7P29e3l+6A6Hg39ZH++AGKfueDh2p2teyk/d8eG5e9Flp+OdXz2G0/Ghe36BT5VKu7u+X7rnh36fp6M3bvgUe9wr33p8vL9bD701s0F9CJfq/r0goyNc+vWswdvbW4dLnvlxPT09dd98+931OuiM3IsBjCWFE0kl//Hxcb7qXwoc4doKYH3oNSP3j4+PvXWEevlhnfLRYGlKO9ouV6A2qIQZtfAwgLluIV0rHoRK81fDWjGaP8L9tqT2dce2hfjUBZcE+Hiw5XCBSgNw6XiKgS8Ca3z/hzNUcuCShROnY6f7WgqXriDEg2nvAbgktmcwdj8fjE2gFe6vfdi5MF8lmCJcqvv3goyOcIlwqf5VutMR5oJLGirJPT/rKVArVIICLTwMYK5bSHPHg1Bp+SrIHaPlI9yvB2pfd2xbiE9dcEkBIg+2DMCl0MmlaYBlDC69dM9HOdmkIZh/suhyIulS1z9Z1T+5BPBzsfms652Wsv4FKMGHhU8yLthrO6UrgVKVQAnrQFLCpbp/L8joCJcIl+pfpTsdYQ64RLBUZrHUDpWgSgsPA5jrFtIc8QBQkpSf5QrkiNHyUbXhgdrXHecW4rMXuDQFIt29inZ9fW0ILlmQcwE23smlMygSn+cTRvoEUQj4XKDQw8PnCa0rAHL67AG2+3rp+6pFz5aASQOcmu8Jl+r+vSCjE7iEa+h7ifZcJ/PHm0eSyjM/Lr4WV/8a3uwIU8IlQqUyy2ArUAnqtPAwgLluIU0ZD0ClLcx7S2NMGaMtzbuGsVL7GqIQHkML8akVLvVO8gC2qBM9+nuPekAFtqHUAS639rcTSdr/BRLhRND7FRpdTkvdl/fafp5yugAfBy71AJTUa8B0D49OR5xaElh0X3+bi9QPwTLCploBE+FSeE+upYYnl3hyqZa12Nw4UsElgqX1l87WoBIUauFhAHPdQpoiHoRKeSOdIkZ5R7hf79S+7ti2EJ8q4dIZuDx0cpKn96XYDhgSQHABUUPfpdQHKfEnly6w5/J9TH0fABPeySXUjacX/9eTRmcgpsssPLKwyNSfdbPwSef9OYyPk+3W1Ihwqe7fCzI6wiXCpfpX6U5HmAIuabC0U5mqmRaAkqRb/bTwMLCl2CyJB6HSOpFeEqN1RrjfXqh93bFtIT7VwaXP00mX0z8X0HKFOwG4NO/BX04pWfBi4c1cqHI7AXX/XVC2zyl92PF96nP9EnR1iurz5Fb/pNOUvmg7b10t141wqe7fCzI6wiXCpfpX6U5HuBQuESytszAAldbpLW8vLTwM5FUwrfc58SBUShuDMW9zYjTmk/VxClD7OJ1KWbUQn7rg0gXK9E/yvHfnk0byHUZL4dLnK2j3wEdOPQmYsfBGgQK37T3MGQYSAoNCcMkHUn0t7PjMyaW7VwGH+lNzu2vHuuE45tWHcKnUjh/fL+ES4VL8aqFlUgWWwCWCpaShcJ3tCSphgi08DGCuW0inxINQqUxEp8SozAj32yu1rzu2LcSnLrg08tBu4ZL6DiYfGN1eletDmlA/Ft582t29bob2AoQ8wOSDossYPbgUgkS23MIiW49xIQ3MhzCp6r8YR7hU9+8FGR3hEuFS/at0pyNMAZd2Kk3Rae0RKkHQFh4GMNctpDHxIFQqG8mYGJUd4X57p/Z1x7aF+GwaLs2FJBZSjfmZBZc8iAToY9MQJLov739h931978TN1HmO6cD6VaAU4VLdvxdkdIRLhEv1r9KdjnAJXNqpJEWntWeoBGFbeBjAXLeQDsWDUKmOCA7FqI4R7ncU1L7u2LYQn1bhUvikUwAKTXotbujk0qHzT1F5bQKnoh6eu5cI0LPsy8YtAGO+B+4i9J9rT7hU9+8FGR3hEuFS/at0pyMkXKonsAKWWvi08DCwpTh68SBUqiuCXozqGuF+R0Pt645tC/HZFFzK+EA/FwQUaSevAx5PXRiQHc7fU3X5UnRCoSIxWrBWCZfq/r0goyNcIlyqf5XudISES+UD28JpJa1yCw8Der613+t4ECrVGS0dozpHuN9RUfu6Y9tCfAiXCF+2Bl/2Pl7Cpbp/L8joBC7hev3Dr12Ll8z/7e3teskzP66np6fum2+/u14HnZF7MYCxpNbRx8dHJxc/VMAqIOtF1oZeM3L/+Ph4VyblslD5SaNAa1AJqrXwMIC5biGVeBAq1R0p/syUiw+1L6d9TM8txIdwiXBp77Bma/MjXIrZncvayPNqi0BJz5lwqewabLZ3wqUyoW/lFThP3RYeBrx511hGqFRjVO7HxJ+Ze03WKqH2ayk9r58W4kO4RLi0Nfiy9/ESLs3br9dsRbjE1+LWXG/sSylAuKTEWOG21dNKWtoWHgb0fGu7B1CSVD6MR20Ruh8PY3SvyVol1H4tpef100J8CJcIl/YOa7Y2P8Klefv1mq0IlwiX1lxv7EspQLikxMh4S6h0E7eFh4HbbOu5A1SyI2I8rCL15RmjcjGh9uW0j+m5hfgQLhEubQ2+7H28hEsxu3NZG8IlwqWyK7Dh3gmX8ge/5VfgPHVbeBjw5l2qLASVMB7GA0rUmzJG5WJD7ctpH9NzC/EhXCJc2jus2dr8CJdidueyNoRLhEtlV2DDvRMu5Q0+wdK9vi08DNzPev2SMaiEETEeUKLelDEqFxtqX077mJ5biA/hEuHS1uDL3sdLuBSzO5e1IVwiXCq7AhvunXApT/D5GlxY1xYeBsKzz18TC5UwEsYDStSbMkblYkPty2kf03ML8SFcIlzaO6zZ2vwIl2J257I2hEuES2VXYMO9Ey6lDz5PKw1r2sLDwLACeWqnQiWMgvGAEvWmjFG52FD7ctrH9NxCfErCpV9++aXjRQ24Bi5rABCMcClmdy5rQ7hEuFR2BTbcO+FS2uATLI3r2cLDwLgK6SzmQiWMgPGAEvWmjFG52FD7ctrH9NxCfErCJTxMM+XpKa6B2xogXIrZncvaCFzC9fqHX7sWL5n/29vb9ZJnflxPT0/dN99+d70OOiP3YgBjSa2jj4+PTi5+qIBVQNaLrA29ZuT+8fHxrkzKZaHy4ytAsOTrYktbeBiwc06dB1CSdOmH8ViqYP72jFF+jUM9UPuQMnWUtxAfwqXbQz0BB7WoYQ0QLtWx/w+NQp5XWwRKes6ES0MrhHXZFCBcWi4tv19pmoYtPAxMUyTeGlApvsW4JeMxrlFpC8aoXASofTntY3puIT6ESwQqNQAVjuG2DgmXYnbnsjaES3wtruwKbLh3wqVlwedppen6tfAwMF2VcAsApRSnlLxeGA9PlbrKGKNy8aD25bSP6bmF+BAu3R7qCTioRQ1rgHApZncua0O4RLhUdgU23Dvh0vzgEyzN066Fh4F5yvRbASr1S9PnGI/0mqb2yBilVjTeH7WP16qEZQvxIVwiUKkBqHAMt3VIuFRit5/WJ+ES4dK0FUPrZAoQLs2TkmBpnm7SqoWHgfnqdN1aUAljZDygRL0pY1QuNtS+nPYxPbcQH8Kl20M9AQe1qGENEC7F7M5lbQiXCJfKrsCGeydcmhZ8fr/SNL086xYeBrx5j5WtDZUwHsYDStSbMkblYkPty2kf03ML8SFcIlCpAahwDLd1SLgUszuXtSFcIlwquwIb7p1wKT74PK0Ur9WQZQsPA0Pzt3WloBLGwXhAiXpTxqhcbKh9Oe1jem4hPoRLt4d6Ag5qUcMaIFyK2Z3L2hAuES6VXYEN9064FBd8gqU4nWKsWngYiNGhNFTCGBkPKFFvyhiViw21L6d9TM8txKc2uHQ6HrrD4f46ngR8vHTPD8fu9K4gyMtz9+DY33w8dM8vyl63fX/vXp4fuofnly4EFaT+5utzXMfTxf50HGwb8snycDyozXtHuBSzO5e1IVwiXCq7AhvunXBpOPh8DW5Ynzm1LTwMDOlSC1TCGFuPB3SoOWWMykWH2pfTPqbnFuJTG1y6wgWBRg/P3UsPBjlwqVcfAy1O3XEQRhl4Zf1roKTvtd0ZePX9nKEZoNSnrZRdoFnMuGlzXRta6x3eEy7F7M5lbQQu4Xr9w69di5fM/+3t7XrJMz+up6en7ptvv7teB52RezGAsaTW0cfHRycXP1TAKiDrRdaGXjNy//j4eFcm5bJQW/gQKuWLcgsPA1Y9ACVJa/u0GI/aYjA2HsZoTKF89dQ+n7YpPLcQn73AJTlh1AM1IfBjYIQHfYYgRq8ftw8PgJ2648PxfPVOXXknscz4hsbCun0CN8KlFLt3Xh/yvNoiUNJzJlzKu8boPaAA4dK9MHwF7l6TlCUtPAxAL0Al5GtMW4pHjfrHjIkxilEpjw21z6NrKq8txKdauHQ6dodD//SP+1rcJ4zpQR8pc8HPDUZcX3c7njq8ijf0etwF5MipJzUmr4+BMunnrg/PnoAp+JpiC0CNcCnVDp7PD+ESX4vLt7roeVABwqW+PARLfT1y5Pb8MACYhDSHfql97jkeqbUq5Y8xKqV811H7ctrH9NxCfGqFSwA+vdNIAyd9BBZpcGPzgBLwezCvqEn9UJ3UewAL38eEvk9HBZ/OkEhOMn2+/ibA7O5VPznVZF//u0EwjJtpO5oQLsXszmVtYuHSly9fOlz61A/KJEW5LsM96myKet1ebKaWW79T8jy5VHYNNts74dIl9HwNbr0fgT09DAAiIV1PxXQ97Ske6VSpyxNjVC4e1L6c9jE9txCfKuESTi3dwRjnlbOz7f0XgAP6SNoHVPMgxfmkkwVSd6eOHFDU+/4lOflkv2DcmRNPLvHk0j/9p92/+Bf/ovv973/f/fVf/3X3r//1v+5tWS3sTb0JV5aJgUse+AEA0hAHdkh1nXdv7ZBHijbII7XlyM9NCZcqW5StDIdwqet4Wmnd1b6HX7hbhkk22nuIh53T3vKMUbmIUvty2sf03EJ86oNLfQBzPk10hTphEGNPKtn8+eRPBIgClNJAqj8GBaci4JKFUuILp5xwGun+tJPqg6CpOdDEk0sxu3NZG8IlvhZXdgU23HvrcIlgaf3Fv9WHAQAlSff02Wo89hSDsbkwRmMK5aun9vm0TeG5hfjUBZf6YAnw5QaKFsIlB9TcfHtAR/q7h0EY1/33OtmTSzIf71SVfnUuPKdrP864WefFax9lhEspdu+8PmLgkj0RZE8QoR7lSFEeSq0d8kjRDnmkthz5uSlPLuVdY/QeUKBVuMTX4AILYoXirT0MACqtIE2RLrYWjyIiFe6UMSoXAGpfTvuYnluIT11waQwOGBAz8ySSBjPDcGlkPHcnl5zx3X2f0gVY3U5GWSA10idB0+5PMhEuxezOZW2mwiULeAB0dLnc6ws2NtVtpA55pLBHHqktR35uSrhUdg0223trcIlQqfxS38LDAIDS3k4pedHfQjy8cbdUxhiViza1L6d9TM8txGfTcCkBaEkLl/pf+i2vwN0gkoJGAsXwqt8doFJ2CeanQRrvt6Et4VLM7lzWZgpcsnAHMMeWj+XH2oXah8rhb25KuFR2DTbb+xy4JP+Y2+IlYGmL4+aY11tvgErUfD3NqTW15hrgGuAaCK8BwqX+X5mbBGBcMDTtJNLpaL/gexsAZJJOhGSTTlvJz+T3v/m+++GHH7off/tj99Pvfup+/v3PfMao5PlQHuoFrIQuDWss2EFdqBz1koZsbDnySOEDeaS2HPm5KeFSs3in7MTnwKWyI57eO08rTdcsZwt5iKjlA5iEtJZxrTmOmuKx5ry31BdjVC5a1L6c9jE9txCfbcGljYCXz5NJ+HLwUOp9uTehzUZinBGY8eRSzO5c1kbAyhiUsVAH9qFy1CMN2dly5JHa9qFy2M1NCZfKrsFme98zXCJUqnNZl3wYAERCWqdC646qZDzWnel2e2OMysWO2pfTPqbnFuJDuESYQaBV1xogXIrZncva5IBLsRAoZDe1fC5UQjvCpbJrsNne9wqXBCzxU6cCJR4GCJPCa6FEPMKjYY2nAGPkqbJOGbVfR+e5vbQQH8KlusACQQ/jQbg0d8der10sXBLgoy8BMzqPewAb5CVFGdrYPGyXlOu2U+8Jl9Zbb+xJKbA3uMTTSiq4ld6u9TAAoCQpP2EF1opHeASsGVOAMRpTKF89tc+nbQrPLcSHcIkwg0CrrjVAuJRi987rIwYuTYU1IXsLmkJ2a5cTLuVdY/QeUGAvcIlQKRDgCotzPwwAKlU49SqHlDseVU56Y4NijMoFjNqX0z6m5xbiQ7hUF1gg6GE8CJdidueyNmvCpbWhUWx/hEtl12Czve8BLvEVuG0t3xwPAwBKPKU0fS3kiMf0UbDFkAKM0ZA6eeuofV59l3pvIT6ES4QZBFp1rQHCpaU7d/72hEu/nv9a3tvbW4dLnvlxPT09dd98+931OuiM3IsBjCWFE0kl//Hxcb7yh5I9bE0BrA+9ZuT+8fGxt45QLz+sNX0IlmqKRtxYUj4MACrF9UwrT4GU8fD8s2y5AozRcg3neqD2c5Vbp10L8SFcqgssEPQwHoRL6+zvS3ohXCJcWrJ+2HaBAluFS3wNbkHQCzdd+jAAoMRTSmkCuTQeaUZBL0MKMEZD6uSto/Z59V3qvYX4EC4RZhBo1bUGCJeW7tz52xMuES7lX2XswVVgi3CJp5XcUG6mcO7DAKDSZia6kYHOjcdGpreLYTJG5cJI7ctpH9NzC/EhXKoLLBD0MB6ESzG7c1kbgUu4Yr+jaG92Mn+8eSSpPPPj4mtxZdfnrnvfElziaaV9LMUpDwMASjyllC/2U+KRbxT0PKQAYzSkTt46ap9X36XeW4gP4RJhBoFWXWuAcGnpzp2/PU8u8eRS/lXGHlwFtgCXCJXc0G22MOZhAFBps5Pc0MBj4rGh6exyqIxRubBS+3Lax/TcQnwIl+oCCwQ9jAfhUszuXNaGcIlwqewKbLj3muESodI+F2boYQBAiaeU1o17KB7rjoK9DSnAGA2pk7eO2ufVd6n3FuJTG1w6HQ/d4XB/HU8CHV6654djd3pXAOLluXtw7G8+HrrnF2V/Ot77P546QJ3T0dhf+zp1x4Pp+zweY+/5f3juXs5+nPFf/asxsuwaD8SlpZRwaenOnb894RLhUv5Vxh5cBWqFS/xeJTdcuyi0DwOASruY3AYnYeOxwSnsfsiMUbkQU/ty2sf03EJ8aoNLV4gg0OgKZQBeMsCZ07F7eH7ujldA1YdFIdh1OI9NxtO3v47/CohO3fEKrwLjPwMyAVe3eun3AtQwd6b32u5TE8KlmN25rA3hEuFS2RXYcO+1wSWeVtr/YpSHAQAlnlIqH+8WHs7Kq7xsBIzRMv2WtKb2S9TL37aF+OwFLr08P/RhzBkavYycgLmHQ4tPLl2h0if46I3jBo9uoESXhe73CVFuGnB+WgvCpfx7+9IeCJcIl5auIbafqUBNcImnlWYGcUPNAJU2NOTdD7WFh7OtB5ExKhdBal9O+5ieW4hPtXDp/HqZ9xqaLbuAielwSUDOoXt4FgAlr7zhVbzQSaTI1+J6cEnDIhmnzb9370PwqVdHAKMBzJ7vCZdidueyNoRLhEtlV2DDvdcAl3haad8LEEAJp5RaeBjYUkQZj/qjxRiVixG1L6d9TM8txKdWuITX0fqvhjlw5hPmCFy6gKIbbNL5Hoz4/J6mvu9Lu+DJpc/vUuq3kfGEYJQFRz5cOh01LLPzO3XHu1cDCZl6sezBvH1oQ7gUszuXtSFcIlwquwIb7r0kXCJU2vfCA1Sys2zhYcDOueY841FzdC5jY4zKxYjal9M+pucW4lMlXMKpJUl7cMXClwvAuX15N04f9dMbEJL2B+OzDyR8uIRTS0jRZgAu3Y1d2tjxW3hk620e/TLdM2AiXIrZncvaEC4RLpVdgQ33XgIuESrtc8EBJiENzbKFh4HQ3GssZzxqjEp/TIxRX481c9R+TbWn99VCfOqDSwJwbqeBzieYxr4Q+/29m3RyacppF3vK6Qy+MD4fLslY+lAMMMjCojG49N71TzbBD1PCpdfpGxpbJFNA4BKu1z/82rV4yfzf3t6ulzzz43p6euq++fa763XQGbkXAxhLah19fHx0cvFDBawCsl5kbeg1I/ePj493ZVIuC3XJh9+rtES9utoCIiGNHV0LDwOxWtRgx3jUEIXhMTBGw/rkrKX2OdVd7ruF+NQFl/pgCQDhBo4snLlBlpvNpczm4euS+lBI6vonl8TO+att179kd++nD8Nu47v1q1+DG4NL4fn252P7YX7L+vDk0vK9O7cHeV5tESjpORMu5V5l9O8qsBZc4mklV/5NFk6FSXaSLTwM2DnXnGc8ao7OZWyMUbkYUfty2sf03EJ86oJLY1DEwJbzKaL+K3ChV+Rur8ZJHxdo5NviVNLYWOBnqr2GS2Y+o6/NxYyJNlsGSzJ2wqWY3bmsDeESX4sruwIb7n0NuMTTStteYIBJSJfOpoWHgaUardme8VhT7Xl9MUbzdEvRitqnUDGfjxbis2m4NOX1tp6tQB0fCvVPLo2BmrAfH3BYmHR5ne8Gvkw9/1pc5+s4Fpdt1xMu5dvTU3kmXCJcSrWW6GeiArnhEsHSxIBUYA6IhDT1kFp4GEitWU5/jEdOddP4ZozS6DjHC7Wfo9p6bVqIT7twKXTiyYdOPuRYDpfe3+2rcTcwMg103dr5Y2X9VnQhXFpvj5/bE+ES4dLctcN2CxXIBZf4GtzCwBRongsm2am08DBg51xznvGoOTqXsTFG5WJE7ctpH9NzC/HZFlzaKSCR1/uOp06/piff3fTw/NLkyZ2tQKBc4yRcitmdy9oQLhEulV2BDfeeGi4RKm1rMQEoSbrWp4WHgbW0TNEP45FCxbw+GKO8+g55p/ZD6pSvayE+hEs7BVa91wA5x1wgKIdfwqXye//YCAiXCJfG1gjrMymQEi7xFbhMQcrgFlApg+tRly08DIyKUJEB41FRMAJDYYwCwqxQTO1XEHlBFy3Eh3CJ4CUHIKHP+euKcGnBpr1SU8IlwqWVlhq7sQqkgksES1bZuvKASUhLjq6Fh4GS+k7tm/GYqtj69ozR+pqjR2oPJepMW4gP4dJ8CECAQu1yrAHCpTp/H+hRES4RLun1wPsVFUgBlwiWVgxYRFcASDqNaLaaSQsPA6uJmaAjxiOBiJldMEaZBR5wT+0HxKmgqoX4EC4RkOQAJPQ5f10RLlWw+Y8MQeASrtc//Nq1eMn8397erpc88+N6enrqvvn2u+t10Bm5FwMYS2odfXx8dHLxQwWsArJeZG3oNSP3j4+Pd2VSLgtVfwiWtBpl7jVEkvvaPy08DNQeAz0+xkOrUec9Y1QuLtS+nPYxPbcQH8Kl+RCAAIXa5VgDhEsxu3NZG3lebREo6TkTLpVdg832vgQuESyVXTaASmVHMb33Fh4GpqtSrgXjUU772J4Zo1il0ttR+/SapvTYQnwIlwhIcgAS+py/rgiXUu7ieXwRLvG1uDwri15HFVgCl0ad0yCpAoBJSJM6X9FZCw8DK8q5uCvGY7GE2R0wRtklDnZA7YPSVFHRQnwIl+ZDAAIUapdjDRAuVbH9Dw6CcIlwaXCBsDKfAoRL+bRd4hkASadL/NXUtoWHgZr0HhsL4zGmUPl6xqhcDKh9Oe1jem4hPoRLBCQ5AAl9zl9XhEsxu3NZG8IlwqWyK7Dh3gmX6gi+hkhyv+dPCw8DW4of41F/tBijcjGi9uW0j+m5hfiUhEu//PJLx4sacA1c1gCAHOFSzO5c1oZwiXCp7ApsuHfCpbLBB1QqO4p1e2/hYWBdRZf1xngs02+N1ozRGir7fVB7X5daSluIT0m4hIdppvNPuVC7/WlHuFTLb4DwOAiXCJfCq4M1WRUgXMoq751zwCSkdwYNFLTwMLClMDIe9UeLMSoXI2pfTvuYnluID+HS/uAEgdO2Y0q4FLM7l7UhXCJcKrsCG+6dcClv8AGRkObtbRveW3gY2EYkLqNkPOqPFmNULkbUvpz2MT23EB/CpW2DCIKk/cWPcClmdy5rQ7hEuFR2BTbcO+FSnuATJoV1beFhIDz7+moYj/piYkfEGFlF1stT+/W0ntNTC/EhXNofnCBw2nZMCZfm7NbrthG4hOv1D792LV4y/7e3t+slz/y4np6eum++/e56HXRG7sUAxpJaRx8fH51c/FABq4CsF1kbes3I/ePj412ZlMtC5efbPRQQAAAgAElEQVReAcAkpPcWLIECLTwMYK5bSBmP+qPEGJWLEbUvp31Mzy3Eh3Bp2yCCIGl/8SNcitmdy9rI82qLQEnPmXCp7BpstnfCpXmhB0RCOs9Lm61aeBjYUmQZj/qjxRiVixG1L6d9TM8txIdwaX9wgsBp2zElXIrZncvaEC7xtbiyK7Dh3gmXpgWfMGmaXp51Cw8D3rxrLWM8ao3MbVyM0U2Lte+o/dqKT+uvhfgQLm0bRBAk7S9+hEvT9ukS1rFw6cuXLx0ufeoHZZLGlGsbuZ/aPmRv/U7J8+RSiZXHPs+vU/K1uPBCAExCGrZkTawCLTwMxGpRgx3jUUMUhsfAGA3rk7OW2udUd7nvFuJDuLQ/OEHgtO2YEi4t37tze4iBSx44AhjSEAd2SFFn86Fy2CG1dqFy2M1NCZdyrzL6dxXgyaW+LIBISPu1zKVQoIWHgRQ6reWD8VhL6fn9MEbztVvaktovVTBv+xbiUyNcenl+6A6Hg3s9PL90Fp6I/fHkAIXTsbuzPx3v/T48dy/v0v6le344dqfzveOP5Xfa21gwv3zdEC7l3ddTeCdc4mtxKdYRfcxQgHDpIhph0ozFM7NJCw8DM6Up0ozxKCL7pE4Zo0lyJTWm9knlTO6shfjUCpfuoNAA2JkEl+78nLrj8fQJTQJw6eW5ezgIdJL6PvSScZ6OBx9u3fW1HDwQ3uxfQ8Kl5Ft5cocxcMmeCMIJIqSoRx6pLUceachuajn8zU15cin5sqLDGAVahUuASUhjtKJNGgVaeBhIo9Q6XhiPdXRe0gtjtES9ZW2p/TL9crduIT57gUtTTjr1AE3vdJMHl3SZvteQI1SubXjf053gLXgKjHAp986+3P9UuKTBj74XsIM8UsAemw+Vww6ptQuVw25uSri0fB3RwwwFWoFLgEhIZ0jFJokUaOFhIJFUq7hhPFaReVEnjNEi+RY1pvaL5MveuIX41AqXQrDocD1ldIM1808uWShk8+/d+yh8+hxHz+42NgIVajF1DRAuZd/aF3cwBS6NwR3UIwXssflQOeyQWrtQOezmpoRLi5cRHcxRYA5ckn/MbeUCTNrKeDnO7awtxoqx4hrgGuAa4BrIvQZqhEv6YVzA0dgrcrPh0h0QuodLp6P+Dqb7+ttYT93x+t1NBCo3XajFVC3kZ/L733zf/fDDD92Pv/2x++l3P3U///7nzTwb5d6zSvuX52EBK6FLwxoLdqTOliGPFO1tPlQOO6TWLlQOu7kp4dIcMsI2ixWYA5cWd5rRAWAS0oxd0fVMBeSXDj/1KMB41BOL0EgYo5Ay+cupfX6Nl/TQQnyqgkvel20Hvthbf4G3wKXQSacgmJK+7mCQhUcWGEm9/s6lh+75BfDEtkU506lwpXV7nlxasmuv01bAyhiUsVAH9rYceaQhu1A52iG1dqFy2M1NCZfWWWvsxSiwZbgEgKRTMz1mK1SghYeBCmUPDonxCEpTTQVjVC4U1L6c9jE9txCfquBSgu/hiT3pdA+WBAJZQOTBJX2SqQ+O+qec+nWtAxPOP349EC7F7M5lbQiX+Nfiyq7AhnvfElzSEEnu+dmmAi08DGwpMoxH/dFijMrFiNqX0z6m5xbiUyNcmnUS6RNMjcEl+ctu3vc2XeDHErhk28bDBIIXaqXXAOFSzO5c1iYWLsmpIX3hlJBXJnVD5Wg7ZgcfMfbaZuo9Ty6VXYPN9r4FuASo1GyQdjbxFh4GthQyxqP+aDFG5WJE7ctpH9NzC/GpFS7p1970g3fvfuZrdD0fvdNSFhCN5TUUsaecdB3vw5pTG6sN4VLM7lzWJgYuTYU1IXuBRaG6kuWES2XXYLO91wiXAJOQNhucnU68hYeBLYWO8ag/WoxRuRhR+3Lax/TcQnw2DZd6YCgFpLAw6b2Tk1A30CX1+juX1Cmouy8HTzEe+rDgpYU84VLM7lzWZk24VBIgDfVNuFR2DTbbe2m4BICk02aD0cjEW3gY2FIoGY/6o8UYlYsRtS+nfUzPLcSnVrgU+oJu/7uSUkGYe7j0/h53Iul01F/unWo89NMCTLJzJFyK2Z3L2hAu8TuXyq7AhntfEy5pgIT7hqVvduotPAxsKbiMR/3RYozKxYjal9M+pucW4lMjXLIP28Xz8vrd8RT8i3TyPU7Bv0qX/HQVgVPx9ZA5poRLMbtzWRvCJcKlsiuw4d5zwiUAJKQNy8ypKwVaeBhQ063+lvGoPkQdY1QuRtS+nPYxPbcQH8Ilwpq9w5qtzY9wKWZ3LmsjcAnX0Ktje66T+b+9vV0veebH9fT01H3z7XfX66Azci8GMJbUOvr4+Ojk4ocKWAVkvcja0GtG7h8fH+/KpFwW6tiHMGlMobbrW3gY2FKEGY/6o8UYlYsRtS+nfUzPLcSHcIlwaWvwZe/jJVyK2Z3L2sjz6p7BUczcCJfKrsFme08BlwCTkDYrJicepUALDwNRQlRixHhUEoiBYTBGA+JkrqL2mQVe6L6F+BAuES7tHdZsbX6ESws37hWaEy7xtbgVlhm78BRYApcIkzxFWTamQAsPA2Ma1FTPeNQUDX8sjJGvyxql1H4Nlef30UJ8CJcIl7YGX/Y+XsKl+Xv2Wi0JlwiX1lpr7McosAQuGVfMUoEoBVp4GIgSohIjxqOSQAwMgzEaECdzFbXPLPBC9y3Eh3CJcGnvsGZr8yNcWrhxr9CccIlwaYVlxi48BQiXPFVYllOBFh4GcuqX2jfjkVrR9P4Yo/Saxnqk9rFKlbFrIT6ES4RLW4Mvex8v4VKZ/X5Kr4RLhEtT1gttEypAuJRQTLqKUqCFh4EoISoxYjwqCcTAMBijAXEyV1H7zAIvdN9CfAiXCJf2Dmu2Nj/CpYUb9wrNCZcIl1ZYZuzCU4BwyVOFZTkVaOFhIKd+qX0zHqkVTe+PMUqvaaxHah+rVBm7FuJDuES4tDX4svfxEi6V2e+n9Eq4RLg0Zb3QNqEChEsJxaSrKAVaeBiIEqISI8ajkkAMDIMxGhAncxW1zyzwQvctxIdwiXBp77Bma/MjXFq4ca/QnHCJcGmFZcYuPAUIlzxVWJZTgRYeBnLql9o345Fa0fT+GKP0msZ6pPaxSpWxayE+hEuES1uDL3sfL+FSmf1+Sq8Cl3C9/uHXrsVL5v/29na95Jkf19PTU/fNt99dr4POyL0YwFhS6+jj46OTix8qYBWQ9SJrQ68ZuX98fLwrk3JZqPxQgSUKtPAwsESftdsyHmsrPr0/xmi6ZqlaUPtUSubx00J8aodLL88P3cPzSzcOFE7d8XDsTu8aFr10zw8P3fOLLhO7Q3cIXtYH2nq+3rvT8dAdT7BR6ctz93A89cd9OnYHW9Ybr2rP8r52DelBuJRnP0/pVZ5XWwRKes6ESylXFH1FK0C4FC0VDRMp0MLDQCKpVnHDeKwi86JOGKNF8i1qTO0XyZe9cQvxqRsuCdA5dIeH5+4lABcE7rig6NzGB0IaVA3Dq8/+XRB1gVB9uBS2PwOoEFwSEHU4dsc7UCUgzMCxTx/9fgmldEy3fk+4lH1rX9wB4RJfi1u8iOhgngKES/N0Y6v5CrTwMDBfnfVbMh7raz61R8ZoqmLp7Kl9Oi1zeGohPtXCpTNwOZxPLQkAOljIcgebYk8uKRAjfTw8dA+jvlUb028Q8nggySt7FyD1eVrK1r88d8eHh97JqBsMU+3MmLYOV1ofP+FSjt08rU/CJcKltCuK3qIVIFyKloqGiRRo4WEgkVSruGE8VpF5USeM0SL5FjWm9ovky964hfjUBpeuJ5HuTiupU0Huq2XT4NIZWF37uPgOvn4n0EefXlL9+3AJY3VOHX36ub5KdzreXvs7w67bKS0Z4/FZv14nfpVP3ZaAaTev0REuZd/aF3dAuES4tHgR0cE8BQiX5unGVvMVaOFhYL4667dkPNbXfGqPjNFUxdLZU/t0Wubw1EJ8aoNLs0+tfAKgK7Q5wxYDY94v35EkoMgDSZcTUof+9yIZ4CPjE6CE9vdw6fM7nQRAfZ6+uo7Jnkw6+9Lf8dQf7+kodafueIVgFqDpuvDpqtmaElgVAVaESzl287Q+CZcIl9KuKHqLVoBwKVoqGiZSoIWHgURSreKG8VhF5kWdMEaL5FvUmNovki974xbisw+4BOiCFKClD2s8yHJ7zQxtTOrAJd2mD5cuYOkKk85wRpXdwaV7OHTzd6s7HT9PK8lY1Kmpd/1KHUFQERDkramlZYRL2bf2xR0QLhEuLV5EdDBPAcKlebqx1XwFWngYmK/O+i0Zj/U1n9ojYzRVsXT21D6dljk8tRCfquCSff1Mv4pm7q8AxzsddP0OpQRwSaCNHZcCPDcYZKBUFOy5AaQrkACAku9b+vwreefX407vnYZasL+cbprTN9tAw9pSwqUcu3lan4RLhEtpVxS9RStAuBQtFQ0TKdDCw0AiqVZxw3isIvOiThijRfItakztF8mXvXEL8akKLjlAxgMqNxgg8OjQ+8Lrc931tFEiuHQel+8rBJdk3L3vaRI4dn29DWDHgUufr8Gd5PuWTp92nyeWrieYrjrJmPRrdfDL9LZGtqcF4VL2rX1xB4RLhEuLFxEdzFOAcGmebmw1X4EWHgbmq7N+S8Zjfc2n9sgYTVUsnT21T6dlDk8txGfbcGkMHBggZE8gmdNQGgadwc7nqShdru/le5c8uHQGS+p00xV04FTSIBy6jFn+it3zC+YnEEr+qp0FSR6cQhumV92vem9DE8KlHLt5Wp8Cl3C9/uHXrsVL5v/29na95Jkf19PTU/fNt99dr4POyL0YwFhS6+jj46OTix8qYBWQ9SJrQ68ZuX98fLwrk3JZqPxQgSUKtPAwsESftdsyHmsrPr0/xmi6ZqlaUPtUSubx00J8moJLGSDDMrh0edXtekLpc3xnOGVOOUk/Bwus+NfidvM9SxqEES7l2c9TepXn1RaBkp4z4VLKFUVf0QoQLkVLRcNECrTwMJBIqlXcMB6ryLyoE8ZokXyLGlP7RfJlb9xCfAiXlp1m8eCSgAL3tTgLh84waf7po/vX5JbNRQMO3pfTknAp+9a+uAPCJb4Wt3gR0cE8BQiX5unGVvMVaOFhYL4667dkPNbXfGqPjNFUxdLZU/t0Wubw1EJ8aodLTUCOz9fl9Ct3Y/cCteS1vCb0yXDirGbdCJdy7OZpfRIuES6lXVH0Fq0A4VK0VDRMpEALDwOJpFrFDeOxisyLOmGMFsm3qDG1XyRf9sYtxIdwqdwJlZoBB8dWbl0QLmXf2hd3QLhEuLR4EdHBPAXmwCX5geVFDbgGuAa4BrgGuAa4BrgG8q4BwqVyEIEAh9p7a0B+Jv/kT/6k+7M/+7PuH/2jf9T9k3/yT7o///M/57MRnw+rWwP6O5XlmR8Xv9B7HjdhqwgF5sClCLc0oQJBBVr4P83ByVdYwXhUGBQzJMbICLJiltqvKPaMrlqID+ESAYcHOFhWbl3w5NKMzXrlJvI/PfSXW7d4LxoQLq288NhddyaY/GtxXAlrKtDCw8Caei7ti/FYqmD+9oxRfo1DPVD7kDJ1lLcQH8KlchCBAIfae2uAcKmO/X9oFIRLfC1uaH2wLqMCPLmUUVy6dhVo4WHAnXilhYxHpYFRw2KMlBgr31L7lQWf2F0L8SFcIuDwAAfLyq0LwqWJG3UBc8IlwqUCy45digJrw6U//l/+eeddiIbU6Y+1lTpto+9RZ9toG32v+wndf/2jv+i8C/ZSN/aJsYGPob5gE0p//ZeHDpe2QZmkUz5/85/9nQ6XbocySad+vv/+++71l9deMynDpStQJik/+RSw8cjXEz3PVYAxmqvc8nbUfrmGOT20EB/CpXIQgQCH2ntrgHAp566exvee4dKXL1+6oQuvAPK1uDRriV4mKrA2XPKGp4GPvre2qEMq9fre2iOvbeQeF+qH0q8j8GisXnzH2GAMU2zRRlILjpBHClubR7lNLThCHinsbR7lXgpY9KrgkgVHyCOFH5tHOdPlCuh4LPdGDzkUYIxyqBrnk9rH6VTKqoX4EC4RcHiAg2Xl1gXhUqkdP75fwiWeXIpfLbRMqsBSuPSP//E/7uw1dYAW/oTaww6p2Ol75KXMXvBp7VEeSr8ugEvSFu31fagvKYf9kI1XZ6ER8kjRxuZRbtMQNLLlNm/92LxAolfCJStL0byOR9GBsPOgAoxRUJrsFdQ+u8SLOmghPoRL5SACAQ6199YA4dKibXuVxi3AJTmhJCeYcFIJp5mQ58mlVZYaO7EKpIBLf/mXf9nhEtA09aOBj763flCHVOr1vZcP+bDlofzXCLgkNtrO5rXvoTqx0350u6n3gEhI0d7mUW7TEDSy5TZv/di8hUtevZTZk0o2b9sxP1+BVwX75nthy5wKMEY51R32Te2H9Sld20J8CJcIODzAwbJy64JwqfTOP95/C3DJA0u6jHBpfJ3QIoMCtcAlgUS49DRRhlTq5B4ffW/rYKNT+LHttI2+/xoBl7T90nvpT19z/GmApO/Fl82H/As00hfsLEyyediF0iG4pAGSvhdfNh/yz/LpCrTwcDZdlbpaMEbl4kHty2kf03ML8SFcKgcRCHCovbcGCJdidueyNi3AJZxcAlDiyaWya469fypQGi5ZyDOWl2FrQOTZ23rk0XZK8L8a2KPz4kfyKT/Wn82P9WXh0Vg+5M9CI+SRop3NozyUhuCShUdj+ZB/lk9X4JUnl6aLtnILxmhlwVV31F6JUeFtC/GpDi6djt3hcFDXsTu9v3cvzw/d8XRLvYdyKRO7h+eXLlQPm34fqr/jyW/78tw92DoZqy17JzAZ0p514+uDcKnCXwZmSC3AJcAkm/K1OLMYmF1Xga3CJahk4RLKQ+lU+5AflH81cEnyMRfaj6XW/5C9BUlia8tsPuTPQiPkkaKdzaM8lHpwyYIkaWvLbD7kn+XTFXglXJou2sotGKOVBVfdUXslRoW3LcSnRrjkwaFYuHQ6HkaBD3yNg46X7vlBgScFvQR0vYfgkoAoZdsHWcfueDycQdl4/+Mggj72pxHhUoW/DMyQCJf4hd5mSTC7lgIp4NLcL/T2QI8ts3nRRZfpe62ZlHuXtklx/9XAJc9njI3XTspi24agkS23+VC/FhohjxTtbB7lodTCpRA0suU2H/LP8ukKtPBwNl2VulowRuXiQe3LaR/TcwvxqREu3WDMsTupk0xjJ5cEGh0ejt3x4TB4eulsF4A/Z2jknT7yQJJX9i5A6nLaCuBH+usDs3sb2DLdHyyaGlPCpZjduazNnuESTiaNpaLB29vb9ZJnflxPT0/dN99+d70OOiP3YgBjSa2jj4+PTi5+qIBVQNaLrA29ZuT+8fHxrkzKZaGm+AxBIe3fs9Nl+h7tvLKYOtjY9GsEQNJtrL3Na1t7b21t3tojH4JGttzm0d6mFhohjxT2No/yUEq4FFKmXPkrTy6VEz+yZ8YoUqgMZtQ+g6gJXbYQnxrhUh/EXGADThshtQ/s5xNLD8/dyxkMfZ44CryyFvJhfd7yOMH00D2/KPhhwNfZ/nQ0ICnwqp5jd+tP9eGBLpb5ry7uRBfCpYSbeCZXhEs8uZRpadHtmAJrwyUBP1PgD+xtinl5vryyIXvUhdKvC+FSyG+oXPrDFbKx5QKN7AUbXY6ymFTAES5tj7KpYEl8eHBJyvSFvrwy1DFNp0ALD2fp1CrjiTEqo7v0Su3LaR/TcwvxqREu3U4uyStpF6ADIIQUIOYMlQ6B18wAfwxksj7gy09P3VFOOYmPz9fdrqebnJNLp2P/1JL4lP7ugdmpO15hGGGSr32buhAuxezOZW0IlwiXyq7AhntfGy6NST0EhtBW2+h71Esq5d6lbWLvvyrY491bP56NLrP2reVfeVKmqpAzHlWFwx0MY+TKskohtV9F5tmdtBCf6uBS4PQJgBDSJTBCfPQBlvpepR7wuYClK0w6j02V3cElHxj5cImvxi2J4Z7bEi7N3rJXa0i4RLi02mJjR30FaoNL/dExt0cFWngY2FLcGI/6o8UYlYsRtS+nfUzPLcRnK3BpGzBhClx677xTTtuYZ5snitaKDeFSzO5c1oZwiXCp7ApsuHfCpYaDX2jqLTwMFJJ2VreMxyzZVm3EGK0qd68zat+To7pMC/GpEy59voo29Uu3A6eeUkAB97RT75STAJcpcIknl1LEZY8+CJeq+1VwNyDCJcKlu0XBgnUUSA2X/viP/9PRgYsNLmvstYetV2fbS97ahdrHlGsb3Mf0OTYOz5eUxX6sLfyFyof82jZDtinqWngYSKHTWj4Yj7WUnt8PYzRfu6Utqf1SBfO2byE+dcKl8MmY3mtx+E6lAITSr76dX22bav8Jq85gyXxv0xlq3L0W5wMj/7U4H0TtEZZwTuH17GlDuJR3X0/hnXCJcCnFOqKPGQqkhEsAHEPDsCBD5732ul782rzty/qw9sgjRXubR3lsn9oebaxPm9dtpG6ofsjWtkMeKcZjfQzldV3q+xYeBlJrltMf45FT3TS+GaM0Os7xQu3nqLZemxbis2m4lPGkkn7oj4dLly/v7n9HU+ALvfnX4nb9F9/0+pl6T7i03h4/tyeBS7he//Br1+Il89d/DV6e+XE9PT1133z73fU66IzciwGMJbWO5E/Ny8UPFbAKyHqRtaHXjNw/Pj7elUm5LNShjwYanp2tX5q3fYg/7VPfiy3ySNHe5m15qF77RBukto3Nww7pWL2207b6XmyQR6rL7L32ifvcaQsPA7k1TOmf8UipZh5fjFEeXWO8UvsYlcrZtBAfwqW4UyVnwGRPSHmnmQKvxlnAcDpe/gqeLWc+Lh571olwqdyeH9uzPK+2CJT0nAmXYlcL7ZIqsCe4BJiCVITS9zofKtfizrGZ2n7IXtfhHmNCKuX63ualTtfre/hEOlQHmxRpCw8DKXRaywfjsZbS8/thjOZrt7QltV+qYN72LcRna3BpE1Dh83U5/Vqevj8dD93D8wtP7qx08mwTa0ZpQbiUd19P4Z1wia/FpVhH9DFDgbXhkgwRwMODGaEytBmaItoiRV+6DeqQok7n5V7nYTPkT9vg3vqAX6SwQ2rtUa5T2CCVOn3v5dHe2qEc6Vg97JamLTwMLNVozfaMx5pqz+uLMZqnW4pW1D6Fivl8tBAfwiWelNkafNn7eAmX8u3pqTwTLhEupVpL9DNRgbXhkgUYS/OYrvYTuhdbWyd5XPA1JdX+bDtbNzU/5M/zJWW4htraOuStT5SnTlt4GEitWU5/jEdOddP4ZozS6DjHC7Wfo9p6bVqID+ES4dLeYc3W5ke4tN4eP7cnwiXCpblrh+0WKtAyXNLSzQUrQ+2G6qRvW2/zenzWfsjW1um83Ou87iNUrm1S3LfwMJBCp7V8MB5rKT2/H8ZovnZLW1L7pQrmbd9CfAiXCJe2Bl/2Pl7Cpbz7egrvsXDpy5cvHS79fUX2HjaS6rop5bat+PHKtP8l96KB/k5leebHxS/0TrHK6MNVYE9wCeAEqUzYAhObhygoR9ux1LZDXqfwqcv0va23eW0r996YrA3sUK59hu49W5TlSFt4GMihWy6fjEcuZdP5ZYzSaTnVE7Wfqti69i3Eh3CJcGnvsGZr8yNcWnefn9NbDFyyYMfmAXZsOfJIrd3UcrRPnRIuzVk5bLNYgb3AJS3EEERBHVK0s3mUSzpUN1Rv203N6zHYe+1L3+vxhMq1DfxaW5TnSFt4GMihWy6fjEcuZdP5ZYzSaTnVE7Wfqti69i3Eh3CJcGlr8GXv4yVcWnefn9NbDFyyMMdCIdTbcuSRWruYcmsDHylTwqU5K4dtFiuwBlyy4ELyuOwErK3Uw9bW2Tx82fKh9qhDWy+1/qxNqN4rR3+hOu3bs0G9rRvyizaSwk6XodyW5cq38DCQS7scfhmPHKqm9ckYpdVzijdqP0Wt9W1biA/hEuHS3mHN1uZHuLT+Xj+1x5rh0hpgSSAV4dLUVUP7JAqkhkt2UBaC2Pq5+Vx+vfHE9BVj4/keKsvh0+tvrX7QdwsPA5jrFlLGo/4oMUblYkTty2kf03ML8SFcIlzaGnzZ+3gJl2J257I2sXBJQA+u0KkhC4OQR4p2yCP1ym0dbHKkhEtl12CzveeGS80Ky4kHFWjhYSA4+QorGI8Kg2KGxBgZQVbMUvsVxZ7RVQvxIVwiXNo7rNna/AiXZmzWKzeJhUsa6oTAjy1HHil8II80VG7rYZc6JVxaedGxu4sCc+CS/GOOFzXgGuAa4BrgGuAa4BrgGsi7BgiXCJe2Bl/2Pl75mfz+N993P/zwQ/fjb3/sfvrdT93Pv/+Zz0aVPB/KE66AldAVgjgh6GPLkUcKf8gjHSq3NrBNmRIukfYUUWAOXCoyUHa6GwXkQYSfehRgPOqJRWgkjFFImfzl1D6/xkt6aCE+hEuES3uHNVubH08uLdm112krYGUqqAkBH1uOPFL0gzzS2HLYpU4Jl9ZZa+zFKEC4ZARhNrsCLTwMZBcxYQeMR0IxM7lijDIJG+GW2keIVNCkhfhUB5dOx+5wONyuh+fu5f29Ox0fuueX9+7l+aE7ngwQennuHtDm0x5AAe2Ql/Y9/9IObU7H7uH5pYPtOdW+0UcvvYyr1+bdjI/5vqbUY1APwqWCm35k1zFwKQSBLOQJ2S0tl36sD9v3kjzhUuRioVlaBQiX0upJb+MKtPAwMK5CPRaMRz2xCI2EMQopk7+c2ufXeEkPLcSnRrh0B3gG4dKpOx5ugOcMj46n68O7B5c8/2c45MGlOSDkDKSO3QltDaBC/6fj4R6UoQ3TawxbA3eES0t27XXaxsAlwB0BPBbyePmQXWy59QlwFCpH/dyUcGmdtcZejAKES0YQZrMr0MLDQHYRE3bAeCQUM5MrxiiTsBFuqX2ESAVNWojP5uHSHRB66Z4fbrApFVy6OzF11y9OK0n/N7B0OSl1ywsoeXk+nk9hvf6tmwUAACAASURBVL/3bVuDKJwv1kw/JVwquOlHdh0Llzxwkwv2eH3lLCNcilwsNEurAOFSWj3pbVyBFh4GxlWox4LxqCcWoZEwRiFl8pdT+/waL+mhhfjUDZfkVBJekfNfi7uDPuqUk8ALDy7Z1+JwkuhdvZJ3Lfs8QXTXTwgu9cpl/H2wdAdUevZ9yHBny9NMTZxmIlxasmuv03YJXMoJfNb0Tbi0zlpjL0YBwiUjCLPZFWjhYSC7iAk7YDwSipnJFWOUSdgIt9Q+QqSCJi3Ep264dIMtgEQW8ti8BUpoB1Aj9hYcoU7gUqjOtrN5+DgdFUwa8Af79/dTd8R3PhEeNQGPbrG/rW9dRrhUcNOP7Jpw6dfzX8t7e3vrcMkzP66np6fum2+/u14HnZF7MYCxpHAiqeQ/Pj7OV2Q8aNaQAlgfes3I/ePjY28doV5+WPmhAksUaOFhYIk+a7dlPNZWfHp/jNF0zVK1oPaplMzjp4X4bB0u3QOhxK/FqdNM9sQT8rcvGO+DIgugJH9pc3ttj6/G+YBFw5bW7gmX8uznKb0SLhEupVxP9DVBAcKlCWLRNIkCLTwMJBFqJSeMx0pCL+iGMVog3sKm1H6hgJmb1x6f/+8//NsdL2rANcA1IGuAn/UUIFwiXFpvtbGnngKESz05mFlBgdofBlaQoKouGI+qwuEOhjFyZVmlkNqvIvPsTmqPD6ECoQLXANcA1sDsjY4NJytAuES4NHnRsEEaBQiX0uhIL/EK1P4wED+TfVgyHvXHkTEqFyNqX077mJ5rjw8eKpkSMHANcA3E7Gm0SaMA4RLhUpqVRC+TFSBcmiwZGyxUoPaHgYXT21xzxqP+kDFG5WJE7ctpH9Nz7fEhUCBQ4BrgGsAaiNnTaJNGAYFLuNb8C2019SXzx3cmSyrP/Lj4hd5p1hm9OAoQLjmisCirArU/DGSdfIXOGY8Kg2KGxBgZQVbMUvsVxZ7RVe3xwUMlUwIGrgGugRlbHJvMVIAnl3hyaebSYbOlChAuLVWQ7acqUPvDwNT5bN2e8ag/goxRuRhR+3Lax/Rce3w8oBAzL21T3V+Le9/BXw+TvzB3PH3+ZbhDMD0dD93D80vX2l9D43yH13jMX4tL8bOv9wHeT1OAcIlwadqKoXUyBQiXkklJR5EK1P4wEDmN3ZgxHvWHkjEqFyNqX077mJ5rj0+KB0zCpeEHfYIQ6rP2GiBcitmdy9oQLhEulV2BDfdOuNRw8AtNvfaHgUKyFOuW8SgmfXTHjFG0VMkNqX1ySZM6rD0+hEsEH2uDD/aXf80RLiXdxrM4I1wiXMqysOh0XAHCpXGNaJFWgdofBtLOtn5vjAdjVL8C5UbIn49y2sf0XHt8CJfyP+gTplDjtdcA4VLM7lzWJhYuffnypcMV+jJu1OsUtl6Z1HnlUoZ2SL0y1C1NRQN+oXfZddhk74RLTYa96KRrfxgoKk6BzhmPAqJP7JIxmihYQnNqn1DMDK5qjw/hEsHH2uCD/eVfc4RLGTbzxC5j4JIFOzYPuBNbDjuktn2oHHapU8KlxIuK7uIUIFyK04lW6RSo/WEg3Uy34YnxqD9OjFG5GFH7ctrH9Fx7fAiX8j/oE6ZQ47XXAOFSzO5c1qZ2uGRBU2qwJP4Il8quwWZ7J1xqNvTFJl77w0AxYQp1zHgUEn5Ct4zRBLESm1L7xIImdld7fAiXCD7WBh/sL/+aI1xKvJFncBcDlyzQCQGf2HLYIYV/5G2K+lwp4VKGhUWX4woQLo1rRIu0CtT+MJB2tvV7YzwYo/oVKDdC/nyU0z6m59rjQ7iU/0GfMIUar70GCJdidueyNlPhEsCPB3qkTl+wsW2QR2rt4APluVPCpbJrsNneCZeaDX2xidf+MFBMmEIdMx6FhJ/QLWM0QazEptQ+saCJ3dUeH8Ilgo+1wQf7y7/mCJcSb+QZ3E2BSxYGWehj65FHCnvkkYbKbT3sUqeESxkWFl2OKzAHLsk/5nhRA64BrgGuAa4BrgGuAa6B8Brw4NJUveRBFsDgr/7qr7o1L/TLND+woMbb0Vh+Jr//zffdDz/80P342x+7n373U/fz73/uPRul+NmfulfQ/rIXy9OvgJXQpSHOHNCDNkjhD3mkQ+XWBrYpU8KlcQ5CiwwKzIFLGYZBlw0pIL/8+KlHAcajnliERsIYhZTJX07t82u8pIfa4+M9YE6dL+HSdqADAVEbseLJpam72Pr2AlbGQM1cwIN2SNEP8khjy2GXOiVcWn/dsceu6wiXuAzWVqD2h4G19SjdH+NROgLj/TNG4xrlsqD2uZRN47f2+OwSLp2O3eFwuF0Pz93L+3t3Oj50zy/v3cvzQ3c8Gcjw8tw9oM2nPUAM2iEv7Xv+pR3anI7dw/PL9STXuY32jT566WVc8G/T01HNRbW7zOGle37Q7SXv2R+70/t79y7aHE/98Uk5r11pQLiUZv/O6SUlXJoKi2LtBSZZ25SAiXAp5wqj76AChEtBaViRSYHaHwYyTbtat4xHtaG5Dowxukqx+g21X13ySR3WHp+9wqU7wDMIl07d8XADNGd4pACMB5c8/2dA48GlVOBGIBUg1tWnhUsKFHljCcGlMwD7BFDiOwDoZI4Cu+7g3HU8qn+WFQNWhEuTtukixrFwSeCOvgB3LPTxbACHUIe2oXLrE/ahctTPTQmXiiw9dkq4xDWwtgK1PwysrUfp/hiP0hEY758xGtcolwW1z6VsGr+1x4dw6QJS+rCoD2xSwaW7E1Me/BkCMhPh0hmSWRjlwiWZ7w0sXU5m3fIClPq++vY89VQfUCNcSrN/5/QSA5dC0CYX7An1l6uccCnnCqPvoAKES0FpWJFJgdofBjJNu1q3jEe1obkOjDG6SrH6DbVfXfJJHdYen/3DJTmVhNfE/Nfi7qCPOuV0OalzO9V0BS1XnxffVzilTvxcyz6B0V0/U+HS2bd6ve06hv74zrDnfBLpoXvovTLXP5F0PX3UG4fo1QdLgEe9E0u9NvXBFYy51ZRwadI2XcR4CVzKBXvW9ku4VGTpsVPCJa6BtRWo/WFgbT1K98d4lI7AeP+M0bhGuSyofS5l0/itPT77h0s38IETSBby2LwACdjae8mLvQVHV4gxAF1sO5u/+gicXpIxPTzYV9L6p6wuPvRrfgYWOSeXTkcFk5z667h6dafuaE9FBcZ9bc/61V6TI1xKs3/n9EK49Ov5r+W9vb11uOSZH9fT01P3zbffXa+Dzsi9GMBYUjiRVPIfHx/nK2cQ6XubCmB96DUj94+Pj711hHr5YeWHCixRoPaHgSVz22JbxqP+qDFG5WJE7ctpH9Nz7fEhXFrhtbjziSOcnvLT6ymiEIDBK3FIr3YGLn2eWJIvLr9BHQWbeoBIbPqQaBB49dry1bibvlrrOu4Jl2J257I2hEuES2VXYMO9Ey41HPxCU6/9YaCQLMW6ZTyKSR/dMWMULVVyQ2qfXNKkDmuPD+HSJ2BZ4Qu9Lbix+TCs6J8+kna3v/hm4NIVOgUgRw8Qfc5dn0C6q1d+TF3vxNNYv6xXsE9pmkkXwqWk23gWZ4RLhEtZFhadjitAuDSuES3SKlD7w0Da2dbvjfFgjOpXoNwI+fNRTvuYnmuPz17h0uH6fUSXk0JyMgivugmcuTspdD7x83mqSMMW84qcAKAz3DH+z/3JX5hL/lqcOnWkQMQNTIXhkjtO9VfwLjCrf3Lp/ayDek1O9dn7zqV3nlwKw8D88Gisb8KlmN25rA3hEuFS2RXYcO+ESw0Hv9DUa38YKCRLsW4Zj2LSR3fMGEVLldyQ2ieXNKnD2uOzS7ikgIh+CB+ES4E20h7ttK/gvYVLctrHA1FO2R3wGhjTrX8fLp3B0h1I+vxC7175PSQ6t70DbAd1Wso58RQ11vLQ5abbvsdCuJR0G8/ijHCJcCnLwqLTcQUIl8Y1okVaBWp/GEg72/q9MR6MUf0KlBshfz7KaR/Tc+3xIVwahwyL4FJ26DINLnnQScruwJYDxXpfYm4hWvZ5jsepFXAUM0/CpZjduayNwCVca/+Vtlr6k/njO5MllWd+XPxC77Lrc9e9Ey7tOrxVTq72h4EqRcs4KMYjo7iJXDNGiYSc4YbazxBtxSa1x4dwaRxabBEuCYA4gyR7Qqp3aglzN6/GuaBIXs+7f8UwBnTQBjqvlxIurbjJz+yKJ5d4cmnm0mGzpQoQLi1VkO2nKlD7w8DU+WzdnvGoP4KMUbkYUfty2sf0XHt8WoJLhBwDcOPzy7pjXuGT717qnWJyYdRAX7TP/uXehEsxu3NZG8IlwqWyK7Dh3gmXGg5+oanX/jBQSJZi3TIexaSP7pgxipYquSG1Ty5pUoe1x4dwiRCE0G1/a4BwKek2nsUZ4RLhUpaFRafjChAujWtEi7QK1P4wkHa29XtjPBij+hUoN0L+fJTTPqbn2uNDuLQ/sEBYxJgSLsXszmVtCJcIl8quwIZ7J1xqOPiFpl77w0AhWYp1y3gUkz66Y8YoWqrkhtQ+uaRJHdYeH8IlggjCqP2tAcKlpNt4FmexcOnLly8drqEv4oaNpNpuSrltK368Mu1/yb1owC/0zrK86HRIAcKlIXXCdf/P3/obHa6wFWs8BWp/GPDGvOcyxqP+6DJG5WJE7ctpH9Nz7fEhXNofWCAsYkwJl2J257I2MXDJgh2bB9ix5cgjtXZTy9E+dUq4VHYNNtv7XLgEsCJpi5/W578k5rU/DCyZ2xbbMh71R40xKhcjal9O+5iea48P4RJBBGHU/tYA4VLM7lzWpna4ZAFUarAk/giXyq7BZnsnXJoXesKlebpJq9ofBubPbJstGY/648YYTYtRyv2Z2k/Tfm3r2uNDuLQ/sEBYxJgSLq2900/vLwYuWaATAj62HHmk8IM80lC5rYdd6pRwafq6YYsEChAuzRMx5cPLvBFst1XtDwPbVXbeyBmPebqt2YoxmqZ2yv2Z2k/Tfm3r2uNDuEQQQRi1vzVAuLT2Tj+9v6lwaQj42DrkkQIKIY/UK7d1sMmREi5NXzdskUABwqV5IqZ8eJk3gu22qv1hYLvKzhs54zFPtzVbMUbT1E65P1P7adqvbV17fAiX9gcWCIsYU8KltXf66f1NgUtjwMfWI48UYAh5pKFyWw+71Cnh0vR1wxYJFJgDl+Qfc/of75Lf8+XN1Svbswac277XOOPL+O5pDXB/5nquZT17cGnq2ORBFkDjr/7qr7o1r19++aXjRQ24Bi5rAD+H8jP5/W++73744Yfux9/+2P30u5+6n3//c+9ZKMXP/tS9gvaX333yeCxgJXRpiBMDeqwN8kjhD3mkQ+XWBrYpU8KlBKCELqYrMAcuSS/6H+/Te91WC2+uXtm2ZlVutPLLj596FGA86olFaCSMUUgZvzzl/kztfY1rKa09Pt4D5lTtSsIlPEwz5WkdroHbGuDJpam72Pr2AlYsqNH/NtjzPeZNuLT+umOPXdcRLo0vA70BwdorQx3TYQVqfxgYHv3+ahmP+mPKGE2LUcr9mdpP035t69rj48Ellv3tjhpQgxbXwNr7Y8v9TYFLopP+d4N3r7W09V57zz5kZ/0tzRMuafV5v7oChEvjkusfclh7ZahjOqxA7Q8Dw6PfXy3jUX9MGaNpMUq5P1P7adqvbV17fFp8gOacCY64Bvw1sPb+2HJ/sXAJGul/N9h7sdFlOu+11/XSDnmk8GXzKF+aEi6dJed/SilAuDSuvP4hh7VXhjqmwwrU/jAwPPr91TIe9ceUMZoWo5T7M7Wfpv3a1rXHhw/Z/kM2daEuLa6BtffHlvuLhUvy7wX56H832HtbPzev2+l729/SPOGSqMtPMQUIl8al1z/ksPbKUMd0WIHaHwaGR7+/Wsaj/pgyRtNilHJ/pvbTtF/buvb4tPgAzTkTHHEN+Gtg7f2x5f5qhksSF/3vlNT3hEstr/wK5k64NB4E/UMPa68MdUyHFaj9YWB49PurZTzqjyljNC1GKfdnaj9N+7Wta48PH7L9h2zqQl1aXANr748t95cSLsm/KfRH/xsDdV4Z2qDO5lGeOiVcgtJMiyhAuDQuu/6hh7VXhjqmwwrU/jAwPPr91TIe9ceUMZoWo5T7M7Wfpv3a1i3Eh38t7vZXuvgXy6hFDWsg5q/FtbA3rb3fT+kvJVySfu2/K+bk4Qep9pHynnBpykqhbXIFCJfGJdU/8LD2ylDHdFgB/sId1mftWsZjbcWn98cYTdMs5f5M7adpv7Z1C/EhXCJQqQGocAy3dUi45O/0KX/3+j3El9YMl0Qn+Wi9Ut4TLsWvE1pmUIBwaVxU/QMPa68MdUyHFWjhYWBYgbpqGY+64uGNhjHyVAmXpdyfqX1Y5xpqWohPtXDp5bl7OJ46Cx1Ox4fu+eX2IG7rX54fuofnl7t2Vzvxezh0h+t18Sftjqf3DunV/v1SdrPXbQ/dwYxR2mtbjAV+JUXZtQ89pofn7uX9Nr/7+b50zw9mDIfD1ae1Px3vbQ8HaCi+jt1J9Ycxue3MXGHL9BavFFoQLvm7f8rfvX4P8aW1wyXRSj5as1T3hEvx64SWGRQgXBoXVf+ww9orQx3TYQVaeBgYVqCuWsajrnh4o2GMPFXCZSn3Z2of1rmGmhbisze4dIYiQxAkAK00/BHIpCEB6nRZzL0GSfChyy4+Tt3xCns+QZYav4VF7+9hICT+7u0/5+LO2/d1P8aLj1D5+xmOAVLJfG5ACyBN4mJ1jdGwRRvCJX/3T/m71+8hvnQLcEn0ko/WLcU94VL8OqFlBgUIl8ZF1T/osPbKUMd0WIEWHgaGFairlvGoKx7eaBgjT5VwWcr9mdqHda6hpoX47AkuCfw4PBy748PtJM8dnNCnhM5Q5wZD5pxcGgImGsbIPfwDuJzHdjpeTx1dxirAByeLPFjkAyHMMwSXLtpcTkWd768ACFDoBtT0uOFXUr9cj6cPyqTN6RknsbTdrS/tn/cXXQiX/N0/5e9ev4f40qVwSXoKzUeXy721RRlGC3vPDrawSZESLkF5pkUUIFwal13/oMPaK0Md02EFWngYGFagrlrGo654eKNhjDxVwmUp9+dS2qecQ1ip7deUis+aylULl07H7nC4Bx8heHI+sXR9pUxAxv0ra2d44Z7gub0OJwDFAiOvLARCxLb/Wtzz9SSPB5c833qO+v7S5zCkubcXYHGBPsejfSUv7Cv6tTgNx0TbawwcgKRtnVfxQpq2Vk645O+ANf3eEriEC7BFj2/oXmY3VF97HeYr8397e7te8syP6+npqfvm2++u10Fn5F4MYCypdfTx8dHJxQ8VsArIepG1odeM3D8+Pt6VSbksVPnoHyzrc295b65e2d7mnWs+LTwM5NIuh1/GI4eqaX0yRtP0TLk/l9I+5Rymqbct61LxWVOlOuGSQI+H7uHh/lUqC08AQSwQOgOJM6AykKl3cuny+hagj0410PAAkK7X9yFblEuqTy6hXPvQc9T3F5tPcHY9efT5Cton1Lmz/5zvRZ9L21v/YbjkjfPW7gaOTkcNAC/+3VicYdKpOw7BJwKn8+uYhEv+DljT7y15XgVkQarHt+d7zJdwyV+nLM2sAOHSuMB6A4K1V4Y6psMKtPAwMKxAXbWMR13x8EbDGHmqhMtS7s+ltE85h7BS268pFZ81lasSLgkUku8dOoMRDS+818RuoEMDmqn3gDxIdXsp06eRevcGlnjtxRfKJe1BmrvTPAJohl6LG55vHy55sEeXyb3SFzDOgisnfwFIHiy6+PdOnY19X5TWvOV7wiV/B6zp95YHlwBdbCrj1mV6Hri39To/dD/kW7fz+tH1c+4Jl/x1ytLMChAujQuMH3hJ8fHKUMd0WIEWHgaGFairlvGoKx7eaBgjT5VwWcr9uZT2KecQVmr7NaXis6Zy1cElA5TOYEcBnD48GQYtJQAFIJLtG+V3cOnzlTX8BbzzfAe/0LumOXtwCeP7/C4rNRfRpH/SCbZM9XohXPJ3wJp+b8XCJYxZwxsp03l979nren1vba1f5JFKW33v5bX/sXvCJX+dsjSzAoRL4wLLDzouWCMvKT/TFGjhYWCaImWtGY+y+sf0zhjFqHSzSbk/l9I+5RxuyuzvrlR81lSyKrhkwBIeuDVwSQOXcLrm9lfN9Gmk8Gtd4xDkPNbeSZ/LKSQpF7+S9k4uyatgn6+uncegQNoFxtxOMUGPS3r7IvLb2AO2gyeS1Mkl9VoaXje8+TavF0a+5taPlzkppfrrz21c5z3bEy75O2BNv7di4ZIHcGQeQ+BmrB5toYfO415S+EGqy+y9bhd7T7jkr1OWZlaAcGlcYGwOkuJjy77+0V90MRfat5y28DCwpfgyHvVHizGaFiO7P09r3beO1T5lnzKC1P76s9pPLjY+W55xVXApAjb0YMUgNOmDoz4wEsjhgxhAoDO8mO3/Ho7ArwuXBubdm+/V7v6vsl1gS3hePozxYU9ojPflpv3Lc3d8fjl/b9ClPzvOoZNO95r5Y96/HeGSv6PW9HurNFwSLSwgQhngkM5DO68OZVNTwiV/nbI0swKES+MC4wdeUnzk/qsCSigfS+e0GfO5tfoWHga2FBPGo/5oMUbTYuTt2dM83KxjtU/Zp/Se2t9tRvu6i43Plme9abh0hS1TgUMYwgACpQYb8HsPaIbHXjdcun2XFPSS+enTTj2od/f9UsNzh8/WUsIlf0et6ffWUrik52KhjtTZMpuHDVKp1/deHj6sHcqnpoRL/jplaWYFCJfGBZYfclyw/vpHf3FXhrrYVHy0+GnhYWBLcWU86o8WYzQtRtivJV36idU+ZZ8y5tT+lupQa/vY+NQ6/phxtQuX+iebgkBkNsDqg5O0cEl8T3gtLjgHc/JI2cW9Fvc5DvMqXwgG+aCsr1OobUvlqeGSt997ZTH7RUmbmsa8FC5pkCPzGsrrOrnX9voedVqnoba2bmqecKnkT0PDfRMujQdfbwKw/poALokv8TPl441lSvsStnbMLTwMlNB5bp+Mx1zl1mvHGE3T2u4501r3rWO1T9mnjCC1v/6s9pOLjc+WZ7w1uNQSZNjMXOX1weOpd2JJwzq5F1h1911TCmZtZq4rjJlwyd9Ra/q9tQQuWYgj89JlNq/r5F7X6/shO6/dUFvry8sTLvnrlKWZFSBcGhdYfrhxifVXBZakfMlHfE35YBxL+53S51JbO+YWHgaWapazPeORU908vvkzM01Xu8ante5bx2qfsk8ZQWp//VntJxcbny3PmHCJJ2cIdupaA4RL/o5a0++t0nBJayH3HvzR5TH3no+hMsIlf52yNLMChEvjAusNQqy/JoRL8Dc+iouFHUtsu5J2dswtPAyU1Husb8ZjTKH66vkzMy0mdo1Pa923jtU+ZZ8ygtT++rPaTy42PlueMeFSXWCBoIfxIFzyd9Safm8tgUsyDw1txvLa1t7rtvpe7JBHirY6r+9RH5sSLvnrlKWZFZgDl+Qfc7LYcUl+zxfmKenXP/qL81x1WYq5w++Yr9T9jvWXon6LY46d9xbntsUxx8aDdvvei2PjW2KNp+4ztb9Y7WhX388Q4RJhBoFWXWtAfia//8333Q8//ND9+Nsfu59+91P38+9/nv0s5O33Xlnt+3MtY5ZHZwErocvCGRm3V4b5eHW6zGuPelsHn7Yc9khhh/yclHApM0She1+BOXBJPGHRS7r3j57r18/X2HRZqvnD95C/HP0O9Zeizo5Zfjnu5WPntoV52THvKR5b0H/OGBmjaarZNT6tdd86VvuUfcoIUvvrz2o/udj4bHnGhEt1gQWCHsaDJ5f8HbWm31sCVuYAmTltZN5z2uVuQ7jkr1OWZlaAcGlcYGyWX9X3I6FM0lQf7T/kM0e/ob5Sldsx7+lhwM4tlWY5/dgx7ykeOXUr6Zsxmqa+XePTWvetY7VP2aeMILW//qz2k4uNz5ZnTLhEmEGgVdcaIFzyd9Safm+tCZdyQ6K5/gmX/HXK0swKEC6NC4zN8mtmuCQj0X14I8NYJN3Kx455Tw8Ddm5biIkd857isQX954yRMZqmml3j01r3rWO1T9mnjCC1v/6s9pOLjc+WZ0y4VBdYIOhhPAiX/B21pt9bU+DSly9f7k4e2TLJ49KwB2Ux9tYGfkLlqJ+bEi7565SlmRXIDZe+/tFfnIGJTTNPK6l72Sxl/JLik2sDlX6GPkv6XdJ2aExjdbbf1w28FmfHHJpjrF2ofYlyO+YtxKOETjX1yRhNi4Zd49Na961jtU/Zp4wgtb/+rPaTi43PlmdMuESYQaBV1xogXPJ31Jp+b02BSxbe5II9tp/cecIlf52yNLMCS+DSr//y0OHyhvl1AJQM1Xm+SpbJZinjlRSfnBvokDZL+l3SFvOek9p+XwmX5siYrM0W45Fs8ht1tIWfmZqktWt8ydhitU/Zp4w3tb8lGtTcNjY+Nc9hbGyES3WBBYIexmMtuPT183/Qj+0RtdTX9HtrCVzKDX3W8k+4VMtPRmPjWAKXZBPBxgfIhFTKhz5j9UNtU9V5m+C/+1/8rsOFfmSssEUZ8pIOfWLttI8hbeb4g+8lbeFjTmr7fSVcmiNjsjZbjEeyyW/U0RZ+ZmqS1q7xJWOL1T5lnzLe1P6WaFBz29j41DyHsbERLhFmEGjVtQbWgEtf1bOH3MtlPyj36qztGvmafm8RLv16/mt5b29vHS555sf19PTUffPtd9froDNyLwYwlhROJJX8x8fH+VpjYbGPbSmA9aHXjNw/Pj721hHq5YdVPnYDwcaGFJBJ0tAHtqH63OV2DtIfwJKk+Mg4YYsy5CUd+sy1C2kT688b05K2nr/YMtvv6y+vrs6e9rF9pLazYw75j7ULtS9Rbscs8eCnbgUYo2nxsWt8Wuu+daz2KfuUEaT215/VfnKx8dnyjAmX6gILBD2Mx9pwCfvXV/NVIyiXFHW6bO37mn5vES4RLq29/tnfpwKpuBd8iQAAIABJREFU4JK4k43N+4QAU8je85GjzNsELeCQMXp2Xpk3xrl2IW1i/S0Zi9d2SZkd8yvh0hI5F7f14rHYqXFg+zDVzE5UQH5m+IlXIOX6i9U+ZZ8y09T+4tXblmVsfLY1q/5oq4VLL8/dw/HU9WHLS/f8cOxO72EA8fL80D08v5h2yv507A6HQ/9S/ZyOD93zi7L/7Ot0PHTH060cdtJfv9z4PvcFn+Hxi/+hcfV1uI2D5fvTIjdc+hp49ujvDJec/V0hbeUq8bFjKTEG9Em4RLiEtcB0ZQVSwqWhodcImLxNsBa4JFp6vxxkzHN/cXjzHYpZijp9gm3qfYr+5/qI1SrWbu44crSzY37NAC5sHznm0ZLPHDHas34p11+s9in7lNik9rfXeMfGZ8vz3zxc8mCRgUca/tzBmNPRwCGAoD60iIVLV/8T4FgIiIXK38X3QSDbqTv25nobux3vdVwDYI42/ZiX0mMJXPL2dl329RMM6bKh/StkBz9DbVPXhcaSup8Yf4RLhEsx64Q2GRRYCy7J0D3AVGLzg4zeJqjhEsbm2Xll8KtTz073AV2mghexl/FhjLrP0L03lpDtnHJvDuLH9vs6cHIJc5LU+pszprlt7JhDfmLtQu1LlNsxSzxSf2wfqf235i9HjPasYcr1F6t9yj4lNqn97TXesfHZ8vyrhUsCjR6eu5ceDAmf/JkHAu794URS35/YHXonomBnTy6hnZRj/Of7KwS6P3kVgkh+uR6zwCXlr6eZtqsDmkAbpsPx2AJckj3v68onmGr6vUW4RLi05d/7mx77mnBJhBJgYD9rb37o39sENfjBuDw7Cz6W5GU8Xh9SLmPAZe3Qp67H3LzU9oH2OvXa6fqhe6+tlNl+Xx24hDlAf2mHMqToO9RPynI75pDvWLtQ+xLldswSj9Qf20dq/635yxGjPWuYcv3Fap+yT4lNan97jXdsfLY8/zrhkoCRh+54tK+4hYGJ91rZ4Otx75c+zq/A9U4/3U7/XCHI6dg9PJ96r+Tp/u5PRgn0WT7+g3pdrz8WvPZn4NL5JFMfNg1rMAw5rn32AB/b5NYlFi55+/hQ2VcFgzw7bx8bs9M+vfYpy8bGkrKvMV8Cl3Ct9dfZautH5o/vTJZUnvlx8Qu9x1YQ62crsDZckoECEsSmsyc30tDbBAE39Gas7TBmXYZu0FZSfJbYiQ89Dsl7/jAmpOhbp6jTqfiWS8aLfnQ97rWfOfd2zH/zn/2drvVrjo5jbazOIXtr90q4FJKqmvIcMapmchkGYtf4ki5itU/Zp4xX/Mm+LCk/YQVi4xP2UH9NfXBJoA++30jfC9Tw4ZKAHg+i+Cd/3rvLa2UORHp/73Ai6QoQ5BU0nKBS97CTPnpw6fzKWn/8t7H545e+7FhtHuM5HRU8cmBSH0iduiPGTkAU/h6uyrTZElySHU5+l6zxSf17cMmYeXKJJ5eWrB+2XaBATrg0ZZMZ2vhSQA5vLF4ZABHGg76RQuqhtinhEvpD6vWLOqQYq06lDm1lbnKVAjyvnyeXZAxaK2ivyzAnL8X8vLqlZdBK0qFPrJ31YbW39XPysWOxdhKP1B/bR2r/rfnLEaM9a5hy/cVqn7JPiY3sj+JTUn7CCsTGJ+yh/pq64NLlO4R6sOYMlDSs0XDlcoomHi5dYBVeVwOw0Smg0aXMngy6QSDY9eGShWEAYoHx905MOV/ofX2VDu0tLLrodf0i8LuTTmGYpefM+7pOY8nP5H//Xx66//W/PnT/5/9w6P7wvx26//d06L2dIXuT93shVIY9HzuSZ4c6ncbapf5dYvvFv2tRrsdY4p5wiXCpxLpjn113Ph738fHROzYnR+ceHx/vyqRcfljlg81D0tAnxgZtYzY9wISpqTfeWB9e21CZB0c8DWLtoA1SbNypUvGrxxITA4xlSmo1eP3l9fzAhL7hC3lJYz8yZsQytk2MnR1zqE0qO8Q01I8uh61OpT5mLLoN7iUeSz5ev17Zkj5ab7s0Rq3pl3L9xWqfsk/Z17Q/ycs1Z4/cW+y1LjK32PiEdLD+QnYly+uCS2MP+WFYol9TC8OWMf+113tw6RO2Xb/kuz+H/kmnfh2hUp16DJ1cwr9JZW/y9hevTPZ3lGOvQV7SoU+MHf69lzOVMcaMZWguKesIlwiXUq4n+pqgQC0nl2TIsrnm+GCj16n0422CMgb8Ax5j8ey8MrTTcMTaLdnYQ2P2+sXYdWrHInW6bQr9vT5smdZYa6XHosc9do9x6/ja+zEftt6O2dYjn9ouZn1I37bfmHZig7aiGXSb0hbz1qkdC/pAubbl/TwFXhcCwHm9brcV1p6kSz+x2qfqEz+Xnj+pwz65dF5bbW91iY1PaL7WX8iuZHmdcOn+xNAFhIThEkBJ6HUy1N/8hE4Kea/LmRNC6kSRgKz+Sav37n3wRNL9ySsZUxwcG4BLn6/W9V+LG9err0udsKW1MXpw6f/+W3/j+m8z2S/w71DsMdhDkJdU9nTY6TT232Wxdtr30D3GGJPqecDeK0Pd2inhEuHS2muO/X0q0AJckql6G54t0/9w19DD2nn+Yjd4aYuHg7E+PkPUS7yxeP56jT4zMW1FgyUfrw9dJv5fnS/0lj5j5+GNb2zc+GXqtfXK9Ji9epRNsZMxin2Kj9evV+b1hXGIvdyPaQcfsWt8iR36YtpX4JVwqS/ISC72Z2HEzbk6VvtUfeLn0fMne6TU44oZ/95srC6x8QnpYP2F7EqWbwsuGfgxCHH68KgPgAS6eBDJ+c6lke/j6b8WZ8Z319aHPSEgdl9u21sIJ3k9LwujxsbH+hpAVgxckr1J9hf8+zOUev9mCtnOLbf7l/wO8T6ef89Oyry9U9qjPNRurfIpcOnLly/d2Jdxiw0ubYsy68MrtzbixyvT/pfciwb8Qu+1Vhz7uSpQE1ySQYU2vOuAZ95gs5MUH12Gfj3Aoe2krfeLQMpj2k6xwzh1ascS8qfb4D62LbRAuymp14cuE9+vGeCSjDFm3PYXZ2hueswhGymPsZNxySW2MWMc6g91Xr9eGex1irGIvXxeP19TnDs2r1+vTI8hdO/9bMWWhXzuoVxixE+8AnPXn9dDrPYp+tQ/g54/+ztG7PXljR9lsEN+q6nV5XXhz4b1V6Mum4ZLd/AmFo5sFS5dvvPpBsosXLrUX79T6vxX7vCX5WK1oV1pwGTh0r/9P/5n3d/8n//YfT4Y+zeM7DnePuSVeftTrJ1uK78PYj/2382Sl4/uFza6LNZ/LrtYuAQINARxLABCHinaIo80thx2qVPCpVyri34HFSBcuhxjxUZr//Hu/VIQQb0N1LZdaucFLrbfJW2hhedjrMwbH8rg9zUTXJKxSR/oZ2ysUo9fiHNSaY+5SWo/GIv1PWV81ifyXr9eGeyRSt/W7lU9nGHMsI9JrT9p45XF+FpiE/pZXeKzlrY6RrWMqeZxpFx/sdp7fXq/EzzdvJ+7Of48P7ZM8lv+WF1e1f41Z17W3xwfudvUC5f6J4+u36PkvYY2GTIJXAr51yd/xkFLipNLAjPiXouT8cSfRsKXjpeGJex/fB1pjeRn8t/4z/+j7t/8r/7j7t/67/6T7q//+q87+1qc7E12f8F+jHLsHchLio9XhjqdxtrpNnK/5HeB/XctfM8dC9qnTGPhkgAdC4Ms5LH1yCOFPfJIh8qtDWxTpoRLKVcUfUUrUBtckoEv2fBCE7cbnvcg6pWJP9s2VOY9SHhtY+28ucT6W9oWvwCnxsIbn5SJH0nl85oBLtl+MX5Ph5gy689rY3+5hvLSVvuDnecztkz7kzbwqVPrSzT5/vvvd3HZuYXy3s90bJnnM7atZ+f5iy2Tnxl+4hWwPx/xLe8tQ9rbPmxePHl7ve5haJ+a4w++4VdS+/HKrE3NeavL68KfDeuvxrnXCZemPYzrB/Mm7uV1wOOp08DN3of+gl4T+kyGjXWtN3ty6eU/+N+7/+uPfjz/Wxf7r+xN2F9QJvsLyiTFJ7YM9jr12ur6oXsZ19yP169XNtf/0nY1w6U1wJJAKsKlpauI7WcpUCNcin0w8+xiy0Qs2QRlY5UUH+9hwNssvbLYtrF2GJNOY/vVbXA/ty1+KQ6loT7QBn2L3esKcAnjkf7nfDBeSYc+1g7ztW08Ow2C5N77WBvJLwFEnj+JR+gTo5+dm/jyykJ96HLoN9bvEg3Ytn7AqNfE1HvGN218p+qf297uLUP7V8xYrL+YNmvbEC7VBRYIfxgP+Zn8b/+dP+v+/N/7b7r/49//n9yTS/rfM7LP4OPtObFl8KFTr62uH7sf+/dWqL3Xr1cWap+7vFa4tBZYyg6XBCDwogahNSA/4PoLv+T+8fHxrkzK5YdVPrKBxIKcqXbi3252ng+MA5vZeWCB/8BGUnykD5SjLBb8oJ32F9s21g5j0mlsv7oN7pe0hY9Qil+i6AN5sUeZpPJ5XQiXrD+vj3NHn/+RsUz51P5wKnNZooFt6wEnrdeYftZfaHzap9x7/doy26bVvPzM2E9oT7R2W8wv+RmU+Xprcq4OnvZeH7ZP+bmRC/v91P6tP2kPX5Li45WhLpTKuGI/Xixi2+aws7qE4hPbt/UX225NO8IlwgwCrbrWgD25FPtanOwb3p4TW+bt915bb38assPvK69dqMzz55WF2ucurxUuCfRZCzBlPbmUO4D0v10FBDjJZwpckn/M6Q1E8nrDk7xng/KY9OvnFz+P2dpxhOytnfi3ZdI2dh5L2sb24c0ltt/UbT1/XtlX9eXVqI8ds6cLfOjU+vMefpaUSV+2D92/vhe7r59rSZfb+5A/aYtLt5Eynbf3nj+vTPxYX56d9W8hj+StH2nj2cWW2T69PHx5dSy77LNaBw846fpW7mPW+BQtvkb8HKFPbRu7p3ljgT9JUe/588pgP5R+Hdljhtou2V9j24b693QJ2caUp/YX0+dUG8KlusACQQ/jIT+T3//m++6HH37ofvztj91Pv/up951L+Bn39pclZd5+7/lD/zqNsfvq/K7TPvS99Ye9HeXadu17ea4VsBK67PcajcEeW488UvhDHulQubWBbco0O1z6V//qX3W8qIFdA3PgkvzQYvOQVD56wzsXODYoj02/RvzfVTuOmLHA75y2GPuStku0iu0X49Rp6rbaN+5tH/hlkzOVvm2/GA9SxBz5sVT8SRtJhz6wGbMbG5/Xx9CYPX+6TNqG2ms76ffVORXjjQegR6fSh/aHfr0yb917/egyzEH36d3rNiXu9Xxz9B8bI69vDzh5ZV7brZaligfWM3TAepS87UPyUi8pPnPWPNpa/1Lu+fPK4GMo1XMZsitVl/N3xpDvUvMd6pdwiTCDQKuuNTD35NLQ3rP1OtnD8DtQ/x4c2tty1glYiQU1Y6DH1iOPFP0gjzS2HHapU8Ilwq8i8K81uKT/QR37j3fPzivz/pG/xM7bdGP9xbRd4xeZjMOO+dWcEMNYPf1Qp1Prz+tDyqw/HXvtz96LnVzSz1Ab2GA81o/Ow0bSKZ9Q/1I+dKEPq4GU27G8RsIl+ES/yFt/Ug4bSfHxxoK6oVT7CNkBOIXqc5d7GqTs83VijOb07QEnr2yO77XbLI0H1q+MW2uv16LtQ+pQhvl6a94rg71O4UtSfLy2Xhnsx1I9n5AtframpCFfKcqtLjo+c/xbf2v9XpwyVsKlusACQQ/jIT+Tf+/v/b3u7//9v9/96Z/+afcP/sE/6P7hP/yHo9+JKT/3ds+ZUubt954/b3/x7Dx/aDv2+8H6078Dpa70ZwtwSWCSBVEpARPhEuFSE3BpaCPzNiLZrIY2OLu5iQ+vD7HDxod+prSFbYq2ofHZPqxd6n/0hrTCHHWKsUmKjx2flHt2tuy1EFyS8Q2tJalDvR6zLsfcPTvUxeoC+7EUfYkdxqLHh/ZeWcxYXheCC69fr8wbC8Y+lmoNhmxjHoCH2s+t8+Y715fXbmmMPJ9zyzzg5JXN9Z+i3ZJ4yFpDexmL1R5rETaSyse2kzJvzXtlZwfmP9b/Un/GffQrrbZdTB4/hzG2U22sLjY+S/1NbW/t7fhsveSn/i4nXCLMINCqaw3MPbkkP//eHhFb5v3+8NouscOehd91yNtU9wtbXWbt184vhUsW+kgelwZAKIuxtzbwEypH/dyUcGkALv3dv/t378CLV4ZXvqROXyjXqa7X97CRMtzr1JYjj1TbbuF+7ZNL3oYXs+HIxoXNS9t7G5ntA21hi/bIS4qPbSvlnp1XZttO/QfkmH1oLLZfsfPKYsYMHWwa29azs2WvBeGSzAvrwaZ6znbMaKdTuffsYrXX/Y3dY6yw8/r1ymLGIvFY8vH69cq8sXhlobGIBik+ePBNlcqYvPmmGCt8SIxS95HaH8aK1ANOsWXwMTedMzf8jNm29ucD61DbSZnOY9ze+vbKYK/TlP68tY6+MG/kvX5RNzVFv7odysZS3Qb3XhsbH9jGpinnK32m9ic+CZfqAgsEPYxHC3BJ9h78vvP2U+x12gZlkpb+TIFLFt7kgj22n9x5wqWEcGku1NGASN9rf7YceaTadgv3W4FL2KRi/iGMf7xrW2/D88rQVlJ8rN0YBEK9tLdtpSymj6V2S/rAvHW6ZB627WthuKTnFbq3Y4ad/iUqZZ5drPbwOZZ6fcSWxYxF4rHks2Qs3viGxmL1H7Jdq8574E3dt8TI03lJP6n9LRmLbetBKGsTynttvTLdXq8rq4v38yH22s7m4dtb314Z7HWq/aPca2vLQuvR8we/ksocQvPQdnPu9Zik/dhYxEa3wb3XFnVIp44vZixTfKb2J30TLhFmEGjVtQZagUuy/8jvBe+DvU7Xo0zS0p8lcCk39FnLP+HSQrgkcCfmGgI+tr1nayGSbuPZ115WK1wa26BC/xBGuaTyj258PH9emf2HOkCRTsVnTNuSdnYeU8YCzXS6ZL627euG4ZLWZIqmVgPrZyjvtY0ti1kHEo8lnyVj8cY3Nhb52S75iZkvHnSH0ilzkBh5/c7RD/16/lBXY+oBIq9Mxh4zN6+tV+b9fMgaRB9y77WLLfO0jm2b2k7GIvPB/LyxpSiDdpJO/di2r2b/ws9crF/xl3K+dnyx4xiyI1yqCywQ9DAeLcEl2Ztkj7QfKbN7Z479z/Ybmydc+vX81/L0X4OXZ35cT09P3Tfffne9Djoj92IAY0mtIwlE7ZAjND7AHKSws3mUS6rr9L22sffWzua1X12He6TWb+15WS/y0WtG7h8fH+/KpFx+WOVjNxDvIcfaSDvP7uzQ/Mdra0zOWWxuSKXQ9qHB0NR78eeNxSuz/YbarmG3pI+zsOY/S+Zr275WBpfs+EJxM5Kcs17bWO09f16Z10dsWcxYJB5LPkvG8v+39z2vslzXej195C/wPGSQQAYJZxBI/CRiCI7RSANbs8YI2RdhQ/LgBcwlIC56JxOJgGyUgRFvbPVIb2Yy8eiBDT6Dd7kGC/zAP4QHAfse2SMLKqzu8/VZvfrbVatqV3VVd38Ffffe316/au1du6q+u7sPi68rFrvW5zxqztfH3ecl2MaI+R2SP8TA7KHv3MvMudk8YnMp6mYIHMtX1DOMjU/EmH3YwxyxMmtvK0j+YfFFMRZLDRbto52JBbKxjLp2bbDD5w75i3JRJrajfKYd48vodMmIXBKZIUJrWXPgmskl3DvZWsewrvVtqn6RSyKXiuSXJ21KdU/geBngDEOflay/DfN9qKP0ds+hPhW51JfEmVLeFi624DEsPvhPoZv1USNXo8sW+jFzZS8DLD6GZWPJxldjL6vLzoPFx+wxjOlmsUwspZczFgvDamJh8TEs+rWHm5qDxZy1x3QNwwNXqSzZjy+0Ne2SD4az82By54i1nRvGp3ReUfdFgbyAHZO3I+oZxuYyw2IsmAOwiX6myzDI+xK2EK/1MV0vZ+dYc4xNTGXtsZiRU1/a+fnzNT2Mq+UGssxeCYv2SnJ98KWRS3e3N81qtTr43NzeNVsCZLNuVuvNrn5/SAhs1jfN7d0jtlmvmvXmvjF7Vj4SKHfN7Y2zf3Pb3MHWCPbNb4x/tUJs5nvdbODPlVSvcK6P5+LPS/VLycu1kUu2XmFtxNrF1jqGQf7UpcglkUuUXGKEDTCUkcBheAkznPUxwinKoR3LGM/S2zXkUhshZIsIW2TYwyzDmC5bmJhc1t5cutn4auRqdKfO84se5FL2PLJjmT03Zi+rm42Z2WMYiyWLZWKx8WAH85GVY7oslizG/NqDTjyY3yhj7axcRhcPXLAJnXhukBtSvkjuXMLLsC8RTywRh8V9aQfGAueGc7Wy64i6lnt2mJzZg4+oZzpxDvhxQd3b9ljGHvPh7fl61l6Uy+TM+4n1aM/6GRZzxYgk00XOzQbahvk4me7Y2NZ5+CfrI6h1NpdGLkWC4IAcGon82ZNVRu54m77uiB+LKU9ePZA8d7fNzRE5xMklO8eDmB58l/B7s70ykioQZXsSy+LdkWsxn2ovn4S7RnIpLlRsHWdY1DtVW+SSyKUjcgmkTYmcaeu3Pv8p2RD++fbrlHahz/m1uPhQafFkFygml7U3l242vhq5Gl228I+Zqxcil7Ypzo4Ry30Wy/iw8WAH85GxZ7ayuswew1h8hsWXSuaX6Wbl2nS9b2avz3kwPx6Dr67S66AOwqKrhPwllDYePlelc2LjFrEXyesj6rF8WxxxXng5H2e0x3RLmLeDetYek7NcDj2YPYbFvDB/FkfU9eNj/dlYIRftmd8YC+z6sWJEksnBHuyz82C6bdiiySUjUUbdWcTInU2z3hI1D0TTw66pw91O/cklI4ZWD7Fv6/vdWMc7l0okEsf9Ofj6Q/z7fIW+QJaJZFouySRyiT/nYf2zcu5D5JLIpSNyqYv4aSOXoNsl4wkoVocdlEzGY5A7p7Jm5xIWEfYwZhj6/SITH9r66LKFKuuDyTGMxcfkGJbVPYVcjY+p8/xC5NI2xdkxYnMti2V82Hiwg/nI2DNbWV1mj2EsPo/Zi5x9mF8vhzqTy/iFH/iqtQf9WMb4XiR3Lvn4SnX4ij78i/MYdfiZo7Rzi2PE4og5MJmIWe7ZEeVizkyHzSmGZeyfyl48L8SG+YR2tmT2GNaVF/NvR9Rl49MVK2wxe4Z1xWIycbxLbZOtPZZLLhnpg6+TPRABtrOIkj9GpDx+Dc7LGEHjiSLb0XOwS8jvVvL1AzImb39H2uxiX6/jjqQy4ZP+Wtxm7eKP9jbNek8u7cimg3M9OKflkivXTnzZNflX//6/Nf/iP/2v5vnz583Lly+b337pr/brk13ztjbF9crwGoytTcxejVx2vWJ+GZa1N7acyCWRS5RcMuKmhqjp0m/rb+tjMfWVZzbmwEQu7W4GWNSyCzJbQLO6p5Cr8YFc+LLmfKOu3XBZfFks2rM4Gcbs+XNCnekyDPK+ZHLMb40c081imVhsPNjBfGTsma2sLrPHMBYfw+ylER/WD4zFB7220vSZLsNqziPae1F4SM36iPZK52G4P38mF/tNhh3sZZvJTYFZjDjnNvuQsdIOFrPlnh3QhQ7asGU6bHwY1mb/1PbYefj4MP4ea6szewzryov5tSPqlsbHZBFrLM0GjmjP8K5YoMtKb8/8Yn50lcwWsEWSS1sS6XiHz8FX2DxRst3hdHPwNTR8LSySS0ZcHBA5gYzxxNSe5Ohjf/uVNXwlbUdKPRI8kQx6JHjiLqXYRiybtc/Lob1jnUA2+Zyp7n6H63EckOc5S5FLx2uxrVd+/cP6NVdp5BI+L379h+YaP3b+/ptJ9s6Pz9X+tbg+hI3JZj6ewGmz39bnbaDeVx56c5cil0Qu4UG67QbAbhjQsxIHk4uYvQww3SwW7ZlvhjF7iNOXTJdhXgd1Jsf81sgx3SyWicXGgx3MR8ae2crqMnsMY/ExzPvFC2VWLuvX+4Btho1pz8Zoah84F18ih75k/R5rq3e9YKO/zUamD3b6lmY75rnLhskzPcPYHGDY1kD4J8bRxx7zkbXH5EJo2ybmBOvzGLPHMIsZNq30h29H3ReF+4nXRz3qGs4wlj/Y6CqjPR97my6bZ5BfFrlkO35WxR/tLpFLOyLJiJbHnU5t5FKROCjsXMrb35FJfqfU/cPvIu2wQzJoez77r8uxHwJ/xHb6kSza+QMhtsLX+/bEUfC3x5dFphTH40rjFbnE1864/mENm6PUziXtXKI7lLrIolpiZkz7Ipd+tn+QxiLCFhn20MYwpgu7vmRyWXtz6Wbjq5GbS5flNGKllwEWM8OiPZsPDGO6fu6gznQZBnlfMjnmt0aO6WaxTCyl8WA+MvYsP1ldZo9hPudtdebXXu7aPrCX9ct8MGxMezZGU/tAHmLJ/EYZ5DfiQ9vsRZth0T5kLB7EDRk2HpCxEkfELPfsiHKxbTrMJ8My9vvYYz6y8TE5Fh+wrrFn9iIGG4jbbAOz0h9R98XCySWciz+HbB3zeVnk0gDSwxNCVn/YiTSIXGJkxtT2mc8ixsglv5Pp+KuEhzudBuS3GItsTUWKiVziz3lxfc6udVPIiVwSuUTJpVrySPqfd+ZVO5e0c8k/0NsCj7aVONgNIysXdUsvA8wew6I9i5FhTJdhTJdhyIUvmVzWR1aO+chiGR+l8WA+MvZqx4P58Dlvq9fEnPXLfDBsTHs2RlP7KOWV+S3JfhqIgJLcWDhevlGaXYuBxczGg8lFzHLPjigX26bDfGaxuewxv+z8I2Z5Z+PP7AHzOiwv0Ye1oWulHTY+Q3WZPcOy9rYBhH9ifOj25wosWy6VXLKveD3uyHnYweO/wmakR/zB74evvNkunzZyyfqObGMHkf8LbwPtt+9I8mTQI0FDY/KxbEmeLnLp8bx3xId2Lk1FAE1pV+TS8Vps61lp/cuudWPKiVwSudRJgogo6iaKhuTonMgl9sDHFrKs3Fy62fhq5ObSZTmNWOllgMXMsGivdEN0nm8oAAAgAElEQVRjugzL2mM3Paab9ZGVYz6yWMZHaTyYj4y92vFgPljuGVYTM/PLMOaDYUyXYUw3YjZGEbPzZ/ayecnaY3LMBzB7ie579PXRZt/8M3ssV0wuYpZ7dkS52DYd5jOLzWWP+WXnX8Is/9mP+cLB8oI+X8b4bHyG6prdaM+wrD0fF+rMHvqsRG481lVfIrm0JZaOiJWHv4bGcLK7po1cKhIDfpcSsen1BtnffkXumFw6/q2kHel0jEeyKLbjzqVIRj2SWf5cVF9WXkQu8bWza/3rWuvG7Be5JHJJ5NLn05BHXYSTyCXtXMKDNBZ1tK3EwW4YWbmoW3oZYPYYFu1ZjAxjugxjugxDLnzJ5LI+snLMRxbL+CiNB/ORsVc7HsyHz3lbvSZm5pdhzAfDmC7DmG7EbIwiZnlg9lh+mC7DmL2snPfb9wWa+fD2snXzawezlz23qGu5Z0eUi23TYT6z2Fz2mF92/lmM2WMYywvzEXVtfIbqmv1oz7CsvUx8TMYwXCMoS3KGi1xyxMLiyaX7xginx990MnLpcBfWY5/+Wty5kmYil/jaydbTtrVtyr4MufTaa6818YMf/vY4MCtLuJdpkyvpl/Bot0/bcqAf9J6JYOkiYC65X+SSyCU8SGORR9tKHOyGkZWLuqWXAWaPYdGexcgwpsswpsuwrO7YciyWLJaJpTQezEfGXu14MB+Yh75k8TGM2cvKZXWntmdjlPXhc4Q602VY9nyZHHz50l6cMweLJaMXZeCP2WMxM7mIWe7ZEeVi23SYzyw2lz3ml51/FmP2GMbywnxEXRsfpsuwqGv2GcZ0WSwMY/aYXMRs7sYPZJZILhkpsN29hK+qoUzuWjL9QTuLZiKXEO/RV/Xo+eZ3I23Wjz9wfq5EyzXGfcnkUnb9Y2sdw7COnbrMkkuMrDGix+Noo0RfbJdwyKGMciUcckPLScklIxD0UQ5Kc8AueM9sWv3JkydHmOE2Ue2ICwhbjKKM6TE5hmV1a+Tm0j3F+db4qNFlOY1Yn5eBbCzRR+1cy9o7hRzzkcUy+SuNB/ORscfWhz7jwXyYfjxYfAxj9rJyWd2p7dkYZX3EPFmb6TIse75Mjvk1zL8wl2RYLCXZNtx82cHssZiZXMQs9+yIcrFtOsxnFpvLHvPLzj+LMXsMY3lhPqKujQ/TZVjUNfsMY7osFoYxe0wug+HaWSq5dI2kQvqcH0iwIzIKJNxqtSXXbm7vmrTNjq8Byo7b4TZxrq6NXGJrIlvrGJZZ66aQEbk08dfiSqSCcBFONgfsELm0W9pqFtCs7inkanzU6LIbS8T6vAxkY4k+bDSZLsOYLsOyumPLsViyWCaW0ngwHxl7lvusLrPHsN3Vefgv88EwZi8rl9Wd2p6NUdbHYZZ2LabLsOz5MjnmN2J4WfalybBYom5X22ziYPZYzEwuYpZ7dkS52DYd5jOLzWWP+WXnzzCmm8VYXjI+bHyYLsNqYmH2MvExGcNYLCVZkUunIw1E0CjXmTkgcomvYX3WtdJ6NxYucmlicmmsgZKdy8uAyCV9LQ4PzZjdaFuJg90wsnJRt8/LwFAfFjfTZViMz3QZltUdW47FksUysZTGg/nI2OuTP2aPYZiHvmTxMYzZy8pldae2Z2M0tQ/LbfZ8mZwfm7Z6PI9Pw9eB2nTb+swOjujDcBYzk4uY5Z4dUS62Sz5ZHAybyx7zy86fYUw3i7EcZHzY+DBdhtXEwuwxjPnInAeTASZySYRHhvCQzOnmicgl/pycXf+wtk1ZZskl+0oaPvj6WelraiUceihLcn1x2BtaWg785hG/qejZs2fNK1/52v6z8g2rm4BXiIZs8C75d4N0bsN/DFzkksglPCBjkUfbShzshpGVi7p9XgaG+rC4mS7DYnymy7Cs7thyLJYslomlNB7MR8Zen/wxe1mMxccwZi8rl9Wd2p6N0dQ+StdM1q/pZw5mz2OfFv6kfZdt08Ph7QEbOpbZ6yPrk8XBsLnsZf0ir75kulmM5cDbRj3aK40Psxd1zSbDmG4Wy9pjcjjHWIpcOh1pIIJGuc7MAZFLfO3ss67FdW7sdpZc8sQNyB+U6EMbZcTRRlmS64vD3tBS5JJ+zHsWAnAIuWQPc34BiQ931mYyJTn/0NZXN8ZR8sHkGJaNpUY366NGbi5dlheGsfiyGLPHsFPYy/qtkWO6WYzlgOmOLZf1wfxmMeaDYcxeVi6rewp7p/CRPV8mh7W7q2TnwbBPw44m1oYv60PdSmaPxczkGJbRzeoxWwyby17Wr8836kw3i7EcwK4vmT2myzCmyzCmm8Wy9rJydu4il0R4ZAgPyZxunnhy6ZN/+KT56c9+2vz2S7v/rLZrG2sWu85rMLYOMXs1ckyXYcwvw5CLU5ZGVBmxUvqUyBqQPyghhzbKiKONsiTXF4e9oaXIJZFLZ0Mu2UXrFxBr+4UH7HOUKcnV6GZ9MDmGZWOp0c36qJGbS5flJWJ2g2HxZbFoj83H2rnGfLD4TiHHfGSxTMyl8WA+MvZqx4P5YBiLj2FZXSbHMOaDYUyXYUw3YjZGEVvaHLd4Mgc7D4ZlbH3qCCgvz+zV5D6jm/XJbDFsLntZvz7fqDPdLMZyALu+jPZK6xezF3XNLsOYbhbL2svKWYwil05HGoigUa4zc8CTS8+fP29evnx5QC7ZdVu6b7NrP4uxdYjp1sgxXYYxvwzz6/cp60as9CVlQP6ghD7aKCOONsqSXF8c9oaWIpc+/7x59dVX6Qdfe7N+1H0ZcbRRellf9/1W95+SXBsOeyi97FLrQ3Yu2eIQF5DswsPkGBbtm8+x5Wp81OiOfR7MHsOyMdfoMh8R6/MykI0l+ijNl7HtZf3WyDHdLJY539J4MB8Ze2x96DMezAfDWHwMy+oyOYYxHwxjugxjuhErPaQyewyL9vqMEdNlPhhmfuLB7DEs6lm7Ro7Fx+xFLHt9RD2Ll/nMYnPZq/HLdLMYy0tmDpTGh9mriYXZYxjzUSNnORC5JMIjQ3hI5nTzROQSvx+z9Y+t46fAMuRSX7KnJB/Jn5JcXzza7dsWuVTYueSJGl/3ZE3E0UbpZX0d/ShZn2HWj09JBnK+9LJLrYtc0m8u4cEXiz3aVuJgN4ysXNTt8zIw1IfFzXQZFuMzXYZldceWY7FksUwspfFgPjL2+uSP2ctiLD6GMXtZuazu1PZsjKb2UbpmavyOnT8Wi8UdDyY3NJbs9ZH1yeJg2Fz2avwy3SzGcsCwaK80PhldmzfRnmFMN4tl7WXlLB6RS6cjDUTQKNeZOSByia+dbF2L9+dTtTPkkpE1Rvjg48kbYIwQQl+Uj+2SXB/c2+xbF7l0YnLJE0q+DhLIY76OfisjjjZKL7vUusglkUt4aMaCj7aVONgNIysXdfu8DAz1YXEzXYbF+EyXYVndseVYLFksE0tpPJiPjL0++WP2shiLj2HMXlYuqzu1PRujqX2Urpkav2Pnj8VicceDyQ2NJXt9ZH2yOBg2l70av0w3i7EcMCzaK41PRtfmTbRnGNPNYll7WTmLR+SSCI8M4SGZ080TkUt87WTrWrw/n6qdJZf6EjZMPhJQTGYOTOQSIZciSWNtfDxZw+QY+VPSifpRl/VHGd8uyXv/S6mLXBK5hIdmLPhoW4mD3TCyclG3z8vAUB8WN9NlWIzPdBmW1R1bjsWSxTKxlMaD+cjY65M/Zi+LsfgYxuxl5bK6U9uzMZraR+maqfE7dv5YLBZ3PJjc0Fiy10fWJ4uDYXPZq/HLdLMYywHDor3S+GR0bd5Ee4Yx3SyWtZeVM79zkku/+MUvGn2UA82B3RwAgSdyia+dbF2L9+dTtU9JLs1BHGV8ilwK5BIjaBgWSR2TgRzKSOQwHHoovQ6wqId27AfubSy1LnJJ5BIemrHgo20lDnbDyMpF3T4vA0N9WNxMl2ExPtNlWFZ3bDkWSxbLxFIaD+YjY69P/pi9LMbiYxizl5XL6k5tz8Zoah+la6bG79j5y8ZSIxd1s9dH1Cvlk+WEYXPZq/HLdLMYywHDor3S+GR0p1irYnyleZCVs/OYk1zCy7TK0+2KUa6Xn2uRS/w5ma1rtgbOcYhc+sP2r+X9/ve/b/Cxd358nj171rzyla/tPyvfsLoJQNhKGLHS2nYsldzwcUWSxvdZnZE20PGykEPp+0p2ooxvMztD/HqbS6ljfvg5Y/UnT54czCP028VqR1xAsg9yTI5h0b75HFuuxkeN7tjnwewxLBtzjS7zEbE+LwPZWKKP0nwZ217Wb40c081imfMtjQfzkbHH1oc+48F8MIzFx7CsLpNjGPPBMKbLMKYbMRujiPXJKdNlWDY+JpfFmF+GMXunkIs+stdH1OszPjXnynQZlo0vK5f1wewxjNljWNQtjU9Gd4q1KsZXmgdZOTsPkUvLJxtECF3XGIlcOn4PLK2nhs9xiFwSuTSY/ALxg9JIG9RReiKHYb4/W4cdlF1+s3ZPLSdySTuX8BCOxR9tK3FkH4SZXMT6vAxkY4k+LG6myzCmy7Cs7thyLJYslomlNB7MR8ae5T6ry+xlMeaDYcxeVi6rO7U9G6OpfZSumRq/Y+cvG0uNXNTNXh9Rr5RPlhOGzWWvxi/TzWIsBwyL9krjk9GdYq2K8ZXmQVbOzkPk0nURFyKqlj/eIpf4cx5b12wNnOMQuSRy6YBcMsKGfRjxAnIHZRfJ4+W8PebPY1625AO2UUadJbZFLolcwkM4Fn+0rcTBbhhZuajb52VgqA+Lm+kyLMZnugzL6o4tx2LJYplYSuPBfGTs9ckfs5fFWHwMY/ayclndqe3ZGE3to3TN1PgdO3/ZWGrkom72+oh6pXyynDBsLns1fpluFmM5YFi0VxqfjO4Ua1WMrzQPsnJ2HiKXlk82iBC6rjESucSfk9m6ZmvgHIfIJZFLe3KpjZiJfaU2cJQgdWIbeFcZ9Upt4Ci77C6hX+SSyCU8hGPxR9tKHOyGkZWLun1eBob6sLiZLsNifKbLsKzu2HIsliyWiaU0HsxHxl6f/DF7WYzFxzBmLyuX1Z3ano3R1D5K10yN37Hzl42lRi7qZq+PqFfKJ8sJw+ayV+OX6WYxlgOGRXul8cnoTrFWxfhK8yArZ+chcum6iAsRVcsfb5FL/DmZrWu2Bs5xiFwSuSRyKfyg+amIJ5FLIpfwEI7FH20rcbAbRlYu6vZ5GRjqw+JmugyL8Zkuw7K6Y8uxWLJYJpbSeDAfGXt98sfsZTEWH8OYvaxcVndqezZGU/soXTM1fsfOXzaWGrmom70+ol4pnywnDJvLXo1fppvFWA4YFu2VxiejO8VaFeMrzYOsnJ2HyKXlkw0ihK5rjEQu8edktq7ZGjjHYeQSPpm/rHaJMnb++M1kK+2dH5+r+UFvECq284d90N9VYucQSpP39S792J/VhRzKaGeJbZFLIpfwEI7FH20rcbAbRlYu6vZ5GRjqw+JmugyL8Zkuw7K6Y8uxWLJYJpbSeDAfGXt98sfsZTEWH8OYvaxcVndqezZGU/soXTM1fsfOXzaWGrmom70+ol4pnywnDJvLXo1fppvFWA4YFu2VxiejO8VaFeMrzYOsnJ2HyKXrIi5EVC1/vEUu8edktq7ZGjjHoZ1L2rm037k0FQFzToTPVDlgdkUuiVzCQzgWf7StxMFuGFm5qNvnZWCoD4ub6TIsxme6DMvqji3HYslimVhK48F8ZOz1yR+zl8VYfAxj9rJyWd2p7dkYTe2jdM3U+B07f9lYauSibvb6iHqlfLKcMGwuezV+mW4WYzlgWLRXGp+M7hRrVYyvNA+ycnYeIpeWTzaIELquMRK5xJ+T2bpma+Ach8glkUuTk0uMWBH2+XZ7nF30ftuc1Z88eXKEGW4Xqx1xAck+yDE5hkX75nNsuRofNbpjnwezx7BszDW6zEfE+rwMZGOJPkrzZWx7Wb81ckw3i2XOtzQezEfGHlsf+owH88EwFh/DsrpMjmHMB8OYLsOYbsRsjCLWJ6dMl2HZ+JhcFmN+GcbsnUIu+sheH1Gvz/jUnCvTZVg2vqxc1gezxzBmj2FRtzQ+Gd0p1qoYX2keZOXsPJZOLt3d3jQ3t3dNJ8Fyd9vcrDdB7q65vVk3m3tHTmzWzWq1Cp+b5vbuvrk3Gze3zV2X/F4m2rd2tG3thxg269y5eP+qhzF1Y3mhuRG5dPweWFpPDZ/jELkkcknkkn5zaUseYQHKPnjVyM2lm33orZGbS5flNGJ9Xgay5xF92DxiugxjugzL6o4tx2LJYplYSuPBfGTsWe6zusxeFmM+GMbsZeWyulPbszGa2kfpmqnxO3b+srHUyEXd7PUR9Ur5ZDlh2Fz2avwy3SzGcsCwaK80PhndKdaqGF9pHmTl7DyWTS49kDV7MqeFWMiSS4SQ2KxbyKUj+U2z3scTySUXn5FYkewqkUsW+5aAaj9fI9pWD74361Wz3jh/R3Gqr5OQXGjORC7x5zy2rtkaOMchcknkksglkUsil7407Ct67CGaYWzRZ3IMy+oyuYj1eRnIxhJ92I2M6TKM6TIsqzu2HIsli2ViKY0H85GxZ7nP6jJ7WYz5YBizl5XL6k5tz8Zoah+la6bG79j5y8ZSIxd1s9dH1Cvlk+WEYXPZq/HLdLMYywHDor3S+GR0p1irYnyleZCVs/NYLLm0JVxW250+W1Jl9UAAlQgBI3P2pA+IlTL5YzZBzsxLLvkYrX7T3NywczVSy/qws8rr4XxVniuh5OMWucSf89i6ZmvgHIfIpYnJJfwyuMrHX0lXLh5zYRe9vha3W/rGfiBlC23WR43cXLrsfCPW52Ugex7Rh40m02UY02VYVndsORZLFsvEUhoP5iNjz3Kf1WX2shjzwTBmLyuX1Z3ano3R1D5K10yN37Hzl42lRi7qZq+PqFfKJ8sJw+ayV+OX6WYxlgOGRXul8cnoTrFWxfhK8yArZ+exNHLJduRsv7a2J1FAmBiZ8tAXdwTdb5r1yoiXHRn1+KJeJmAeyaUdoTPO1+IQ633jdxnt42E7lw6wXby3tkMpnKPZu7m9dbum7pv7A91H33t/JSJO+KK/aidyiT/nsXXN1sA5DpFLIpf2fxpPpM8j6XOqXNhFL3Jpt/SN/UDKFtqsjxq5uXTZ+Uasz8tA9jyiDxtNpsswpsuwrO7YciyWLJaJpTQezEfGnuU+q8vsZTHmg2HMXlYuqzu1PRujqX2Urpkav2PnLxtLjVzUzV4fUa+UT5YThs1lr8Yv081iLAcMi/ZK45PRnWKtivGV5kFWzs5jaeRSf2JkRzrtdiH5upEtO7Lm4DeXHoiVR3LJkTIPu6WM3Nr/zlMrgVOyv4tjFXdbud97gv3N2v8mFOwZWVbAD0g3/xU9dx4ijxZNHnXNcZFL/DmPrWu2Bs5xiFyamFyaY1Dl8zwyYASWHSKXduM19gMpW2izPmrk5tJl5xuxPi8D2fOIPmw0mS7DmC7Dsrpjy7FYslgmltJ4MB8Ze5b7rC6zl8WYD4Yxe1m5rO7U9myMpvZRumZq/I6dv2wsNXJRN3t9RL1SPllOGDaXvRq/TDeLsRwwLNorjU9Gd4q1KsZXmgdZOTuP8yaXjISJvz20I3YeySZH0jhy5/hHvdfNxsilA/Kma3cQyKBA7OAreihB9hwRVZEcerRnO7hAQNkOpd1OprJ8F2Gh/jBGGJMFliKX+HMeW9dsDZzjELl0AnJJfxntc/2uE/ldJ5FLw37niC2g2YfZU8jV+KjRZXmJWJ+XgWws0YfdyJguw5guw7K6Y8uxWLJYJpbSeDAfGXuW+6wus5fFmA+GMXtZuazu1PZsjKb2UbpmavyOnb9sLDVyUTd7fUS9Uj5ZThg2l70av0w3i7EcMCzaK41PRneKtSrGV5oHWTk7j0WRS63kz+FfYcPvJY1KmoxBLm13Pz0SWtuv+eErbj3Ipe1frnM/8r0730gu3TeHO5/Oh0AZddwWSBDVnJ/IJf6cx9Y1WwPnOEQuiVwS8UOIn1MQgiKXRC7hIRyLP9pW4mA3jKxc1O3zMjDUh8XNdBkW4zNdhmV1x5ZjsWSxTCyl8WA+Mvb65I/Zy2IsPoYxe1m5rO7U9myMpvZRumZq/I6dv2wsNXJRN3t9RL1SPllOGDaXvRq/TDeLsRwwLNorjU9Gd4q1KsZXmgdZOTuPRZFLhCTY/dbQXfvXnFpJqUeiZ//Cf0TyPJAyBXLpeJeTEV1m93Gn0db2llg6/jHu/V92O/IbyaJDe1u9W7+bql1+f34kj+o7H+JN5BJ/Tmbrmq2Bcxwil0QuiVw6I3IpvujEhztrM5mSnH8I7KvrFzLoZu3NpZuNr0ZuLl2WU4ax+LIYs8ewU9jL+q2RY7pZjOWA6Y4tl/XB/GYx5oNhzF5WLqt7Cnun8JE9XyaXxdh5MIzZO4XcUB9ZPXZeDJvLXo1fppvFWA4YxuwxOYYxXYYx3SyWtZeVM78XQS4VyZRDsmZPsByRPEOJh4L9UjxHfqN+aD+QZvuvx9kPlx98bS+2h56H9PZzozR2J8Q9ufTJP3zS/PRnP21++/AXn+3axvsIu85rMLYOMXs1ckyXYcwvw5CLU5ZGZhm5VPq8+PUfmmv42Pn7n73xv+X87Nmz5pWvfG3/WfmG1U3AK0RDluRT7IKJPl599dUjvwzL6EHG9P3H41Zn9r08q8MG9L0M+mAXJfA2HfS1ycIXZJh99E1RDt25NAcLLZ+XkQG7wehYTgY0HssZi1IkGqNSZqbHlfvpc1zj4RrGR+RSDbESyKAuAuKIXNr9VbnHr/hFe7EdyCRib0kkiWIZNrfsmnz//febjz/+uHn+/Hnz8uXL5osvvjhYyq5hbTo44YU1tHPpQncuMaKEYZE0aZMp9QFH6W0yzPeX6l4PdZTQiW3DPebrsQ82fBnlfd8U9SHkUokJFl5myZUb5UZzQHNAc0BzQHNg/jnAv0J1+HtBS5K5VnKpPAbka3RF0iiSPx1kAiWDAmFU9HVse7M+/gqeCJ3jPJ1bTuyafP3115s333yzefr0afPee+81H3zwQXGnjNb9+df9ax2DuOEIm5G0c8l9ZczIF3yMbEEdpAxKT8QwzPeX6l4PdZTQiW3DPebrsQ82fBnlfd8U9SHk0jVsJdQ5Trdl1BZ45Xe6/PbNrcZjOWNRGjuN0XxjpNzPl/vS9eDxIeNjpEXzz//9bD5LJ5fOjRgYFO/DX4MrE17H5OTBX5PrQUgNik/223/za+T82DX5P/7nu83//j9/33zyf/+x+emLXzf/9M//7+DZdsja5Nc21Zd97zmH8bE5KHLJETMlkqULZ/2GtX1KpI23hTpK6MS24R7z9dgHG76M8r5virrIJS1ep14gdcNd1pzTeCxrPNj1qDGab4yU+/lyz66FiA0Zn0guvfbaaw0+nnQCZmUNHnXb2tYX/YpcOv+dLiKMLmsMRS4t+75g94kh94Z4fzn3tuXg6smlSKzEtpErDPM462dYiagx2dLH+4E+s+0xX4d+H/vwM1VZSy75hyB/EY6FR5to97UPPZXz3xD8gq9x1HjomuyeA/6asXzZdRPzVrqWopza3fn2Ocrk3uTZmHg7qvfLezZfmfGJ14Ynl6yPkT1j4d42iCNgiAvt2I+2yKXLIiZENJ3/ePYll3CtW+nXthLuZVQfdu+I94ZSHktjUMK9HTaevt/qGTtRZ6y25eCiyCWQKihBjsS2J1wg40sQMcDQ9iVs+BLyJcz3+zqLz9uI/bHtZWPd+ynVmb2S7Bh4DblUuqjGwuPFBbso0Y82yoijrXLYAj123rDgl8arhI8dh+zt5oPGYxnXRdt8xBiZjF0fXddI7G+zrb728e/KfWlMlNf2vI6Vn67xideCtecil8y3J5JAHnksylhb5NL5kxEilC5rDPuQS3YN+/UObZToi23gKofdS/y9oZTDmHO0UUIvthluMlGuqw07U5WWg6sll8YgSdpsGGHT9vG6JXIHOEroxLbhHvN16LSVfeXbbGX6zoVc8heor9sFiTbKqS5S2R22wMe8YcGP44U2SujFNnCVGo9rmQO4ZnC+8ZroakNPZf9rpiv3yGkcA+Aq++e8T866xieOi7U9ueSJHU/2mJzvi230AUcZcbStjDIlLOqIXLosYkJE0/mP5xjkUlznbH2ImNrD7x/x3sByGXMe29BheAaLMrEN+1OVloOLIZciQeLbvp4hP5iM2Wj7MJ0sVooPOErYi23DPebr0IGM9cWPlzlFvYZcihcDLhqU6I/tiMf+2DZ5j/m674s4/KgcvjhPkTss+HG80EYJ37ENXOU446rxGCePU85HjBF8xGuiqw09lf3Huiv3yGkcA+Aq++e8T86y4wObNk4lcsn6QOz4eokE8jK+zuRjf8kPcG9D5NL5kxEilC5rDEUuTbuuY72uKeO9gdmyddnjsY0+hmewKBPbsD9VaTkQueT+KlwbsVIibEDatOl29ZVsA0cJO7EdY+jqhx2UTB59U5RjkUv+gvF1u2BiO2Kxf2jb9PxnqotVdutuKljw28ZZ41iX4z5ztGs82sapjx/JDh9TjBFy2DUmsR96KvuPQVfukVPlvH9ukbuaMjs+5gNjxMgl62PEDrCx+0t2GS5y6bKICRFN5z+eY5FLtq7gU7MOSvf4/hPvDSxHlnuP+zbGxWOQZZj1MbzNDuxNVVoOLoJcKpEjwFGCKLF25gN5K6ONtr6MbW+PyXufXhZ+ow5wr9eFoZ/ZR98U5RjkUryY5mp3+Z3q4pXd40W9LSdY8EvjVcLbbKqv3xj4fHWNh8namPiP11d9eO6zucMYQb7rGon90FPZf6y6co+cKuf9c4vc1ZRDxieSSzZ2IHVQRsy3fX2ofEnP8Ghf5NL5kxEilC5rDMcil/zaZ9e9b6ted0+J9waWz5jz2IZOxGM7K1fSg/7YpeXgIsilLgJkDPIkkjmx3RXDkH7EjTJroyQfY0Y7a3csuVpyiV0oEbvgaz8AABPLSURBVPNtX8dFFDHf9vUu+Sgb29BXWbdg1+YPC34cH7RRwk9sA1c5zjh2jUfMs8ZjnLzHvLa1MUaQiWPQ1Yaeyv5j15V75DSOAXCV/XPeJ2eZ8Ylj48kl6wPR48uIo43SyzJCyMv5eh89yIpcuixiQkTT+Y+nyKVp1/U+94CSbLw3MDlbmz0e2+jzuK+jH2Xs62pDb6rScnAV5NJYpIjsfN6MkYMacileNLg4Io42SsihjLhv+3qXfJSNbeirnPemgAU/jg/aKDFOsQ1c5Tjj2DUeMc8aj3HyHvPa1sYYQSaOQVcbeir7j11X7pHTOAbAVfbPeZ+cdY0PG5dTkkvmHyQRK2N/bJuOyKXzJyNEKF3WGIpcmnZd73MPKMnGewOTi/eH2IaOx30d/ShjX1cbelOVlgORS8nfXBqDVJGNHTm1ZHIpXpS4+CKONsqSHHCV894UsOCXxquEa9ymGTeNxzR5HXO+Yoxgs+saif3QU9l/rLtyj5wq5/1zi9zVlF3jw8Ylkksm4z8ggbow9HfJo5+VZsPjsOlLkUuXRUyIaDr/8RyDXLJr3K99se37VO9/f4n3BpbDmHO0UUIHbZTAYxn7u9pRf+y25UDkksilUXYj9SHOasklu3D8BxdGF4b+Lnn0xxL6Vvq+Eu5lVO+/SI+ZM7/gl8arhI8Zh2zt5oHGY97rITMP/RiZfFz3gOG6ydiUTG7cM7lH/pXTXE7HzFPX+OCa8KUnlzyxM3bdfI5hc7Hk0t1tc7PeNAdkyWbd3NzeHWL3983d7c32r/RZ7o8+0UaHPLN/EMP9+ZMXOp9lj2Efcgn3B6xBfv0DZqXHVa+/l8R7QymnpTFgeNc4sX5mpxTL2LjlQOSSyKWzIpfGvgi8PXaB+n7V6xfeuXKYXfDniu/a/Go8ln8taYzmGyPlfr7cZ9biIeMjcumPzR//mPsckxybZs0IotVqRyq1kEvrTZ4wMDKqj/y9EV2rdbO5v2tub26a27tDX5v1qp89EVRHBOHxXDjM8TX19yWXMmuZZMa91wy5N7SNwTm+l1oOJiOXbHeKPspBaQ40TXMw+WwiPnny5AgzfOyLtXQhn+NFXDoX4Yc3jFPNIeX9MO+lfGg8cnkq5e8UuMZovjFS7ufLfebaGjI+pyKXxti1ZDYufecSI5HadjodyxuhZMSSkR2cXNrhkLleUuSaCKC2c/35z3/efP3rX28+++yzQSSayKVl3xfs3jHk3tB2zznH91LLgcglkWCzkIBLJJfaLnD1LX9RbxujsRf8Nl/q654rGo/uHM09jzRG842Rcj9f7jPX3ZDxEbmU27Vku5vaXtC3u4XiV9rm2Ll04LNELt039wdyIphax/YKdm5973vfG0wwiVxa9n3B7h1D7g2Ze845yVgOJiOXjDzQoQywDNT85tI5XWCKdTk3Ai34yxkLuy40HssaD7ZWaYzmGyPlfr7cs2shYkPGR+TSOOTSbndR2A20We9/U8n/NlL6a25O38ap7YMdTJu1j6GFXLrfNOub2+buCoiTayeOsuc/lGASubTs+4KebXfjY/fHScmlPj/yLNndX1K7hjyIXFr+Ahkfps+9PeRl4NzPecnxazyWvwZojOYbI+V+vtxn1s0h49NGWCyxb5Ffi9v+xtFNc3OzalZ+91Jhd1Db19xWHYSP6Xqi6pA4iIRRG7lkfZ6I0u6lw1xeZz6++c1vNt/97nfbd+kFQlLk0rLvC3bvGHJvyNxzzknGciByST/ofRY/6G2TVR/lQHNAc0BzQHNAc0BzQHNg2jmwOHLpYXfRjvAxwmbV7AmiArnUl8RoI6MOiaY+5NJ9c7jL6TrJlL5jccnyP/rRj5ovf/nLjf0GU5/ztGvy9ddfb958883m6dOnzXvvvdd88MEHejfS++Hi5oDIJZFLiyeXfvOb3zQ1H/uhcDvsu/wqlQfNA10HWge0DpzTOlBz/5Nu3fPDteZvWeTS7q/F4StpeCG3v8a23cE0ErkEu0flkf0+5JJ2Lh3lM+zIuab+ocSS5ciuyTfeeKN5++23m3fffbf58MMPm48++qjX7+bas8815VvnOg+ZfZHk0quvvtpKmLB+w/zHfz2Nycd+r4s6ZNr0WV/EYI+V5iPKA2PywBDbHGXfr8XZw93Qw3wZuXROLxJ68dWLr+arCDCtA1oHsA7U3AOH3juld90ZWBa51PGCFMmfAb+hZC+h+Z1LkTCy9k1ze8fijEQUkxF2DSSA7VQasmMJuQG59PHHHzfPnz9vXr582XzxxRe9FyrYU6nrbqo5IHKphZwB8cLIG/SVSq/j61Ge9TEMeqyPYUy+TQ7ypyiHkkv2oN33A3LJVl88qKvUi7vmg64HrQNaB85lHQC51Pf+J/n+zwzK2S5nZ00uDdwZY+RS3B1Vevk6lH34mp7/MXD8plMkvgbGVopD+HkRBL/85S8H7xxaOrn01ltvDT63tnn8zjvvNENsf//732/ip82P74t6pbbXYXWL23+YzCViIpdGJJc8eVOqe/IGMijRF9vArWR9DIOO7/N19M9RzkEu6UVSL5Ln8iKpOEV8ab3SeuXXAZFLIolOTXpdK7lU/HF1kEV7cii3I2mzLu1oOi9S5BJfgM/tnNrIJSMwssdU5/03b/3N6OSSEUt/+9bf9rZrZNBf/vKX/edPf/rT9udVDM+cv8l99tlnrZ82WyCUoq8SHuXOvS1yKUHYZEkZyKEEcRPbDPcyvg5ZlKyPYUy+TQ7ypyjnIJf8g7pe3PTipvkgAkfrgNaBc1kHRC6JXBK5tEAyxr5+t940JULKfhPq8IfAF3gOe7JMsS39hb6NXPr2t7+d5ZZS5MqQXIxNLo1NLP34xz/e7mTKnBvIJZQgmny7i1wq+TGCqdQ3NV5LbkG/6xxELj38oLcRL/7jSZYsKVOSY3aZLDCUPgbUWR/DmHybHORPUY5NLtmNvfTgha/F6UVSL5Ln8iKpOEV8ab3SeuXXAZFLIpdKzzhT4We1c0kEyWwvq1O/DMv+I+k3NrlkBIGRUtlPF6EwJrlkxNLTt572ntdG+LAdS0Ys/epXv+pFLoFIaivZ/OzKk+lkZJjtWsz81viGfpeNqyWXjGjJki1dcrDFSiNron5sR0Kn1A8cJfRiGz4NL32gO0c5JrmE/zEqPWCBXPIP6npx04ub5oMIHK0DWgfOZR0QuSRyqfSMMxUucunxpb72hU76yuUYc4CRS9/61rd6kUN2z8vE8oMf/CAl521FcmmIDbNnxBJs9bHRRSz1JZewW8lKEEzArG0ff/6odxEvJpeRgb0xS5BDQ2x6XV9ntq6WXOpDqjDy5pT68IU4UEYcbV96WV/3Mqeuj0UugVjSziURBSIKRBScC1GgOLVe9V2vRC6JXJqKRCrZFbkkQoS9NAqbb14wcgl/LW7Mr8WB0EGZHXMQQiYPXZRZG0Ys/d1bf7clbaCLss0GyJ5YYseSEUtd5BIIk67SE0wsJtNnuMcyMl5+rDrObYg9r+vrzJbIpYevxbURLLWkDNM3rO0T44k2fNvX2/Ta5KLelO0xyCVPLGXIJb3Q6YWu7wud5EVYad3QurGEdUDkksilEgk0FS5yaT4Sgb2sCdN4ZMglI2L8x55h4tE1l0DmoOySR38tuRR/Ywn+UcIPK41U+vOf/3zwlTjDQCp1EUtm0wiTrsNkTkUugcBpK1kuPNam6/u8TqkOeev3dSYvcunha2tGvLR9usiWvsRNmzzri5hv+3qM0/f5epQ7ZXsMcskeqDzBVHrAwtfirN8OlcqD5oGuA60DWgfOaR0QuSRyqfSMMxUucklkBntpFDbfvOhLLm1fesg/bWMYiRzf9nVmA+RSlPNtX/c2/FfhDI9yvu3rsNFFLlk/ZEulESZtBwgVs4VPm60hfV4H/tpKL8/qbbq+j+l6DLJdGPovllwyIoV9jETpS7Jk5DMynsBpk499sQ07wFF63LCuD+RPXY5FLtlDFQim0gMWyCVbMExGpfKgeaDrQOuA1oFzWgdELolcKj3jTIWLXJqPRMALmkqNgZ8Dc5JLjNDxsVm9i1wq2Yg7lsxWlEUbZfTdRi4ZMQJ5+/qg1VECt9LkcPi6YWh7W1431k2OyQJnfdHGFG3472sbeqxkti6SXOoiSyIZM4Z8XyKnr3xbjH3Pp83WKfrGJJfswSrztbhzepHQi69efDVfRYBpHdA6gHVA5JLIJZsLp/yIXBKxwV4ahc03L7LkEggSI2LYEcfQEza+DjmGoQ+lyZTIJZNpswGix8v4uveBeiyxkyiWIHFQwhdKb8dk7CiV6PM6XXWz5T8mH9tdNsbsh+++NqHHSmbrKsmlUxAo8vF5U8rB2ORS2wOXdi7pBQ0vaCpF2NjDgeaB5sG5zQORS6clVtqeKa6lT+TSfCQCe1kTpvHIkEt2b/OHkTTx8HMJJE4svUxXHbpt5FLWBmyh7NLr6vdkiMmCVELp9SHr82WYP6ztdYbW4Wsse9k44Dcrb3JtOqU+kUuJH/QukSTCywRSW27mIJf0QqkXSrtBaB5oHmge6Do4t3VA5JLIpVOTWiKXRGb0eQGV7PTzZQi5ZM87RtT4A2MVCZzYhlxb6XWMXPLtNj3fF3Vi28v2rYO8QQlSCaW3ZzJdB+x4vaF1szWmvUwcQ3y26ZT6RC6JXCruMGojiGr65iCXbME4txcKxSsiRPNW163WAa0DIpdELolcmv7lPfNyJhmNw1xzYCi5FAmTqeI/NVGSOQ/EhBKkEkpvA0RJV+l1VOfrgcglkUtnQS4ZITX08+TJExFL+jHz7f1VL+p6URdhJ8Lu3NYBI5eG3v+kN/zZ4Zpzt8SdS3e3N/s/4oI/5oLy5vbu6OsqfeW3L4p3t83NenNoa7Nu+tpfRRv3982geJjvzbo5tH/X3N6sjnKz3tw3m/WqsdJ8W6mX4fPNQRu5ZIRI9tAcON85cC5jNxm5dM03ZZ1798OcLYJ+8lndSKCIAbe+mo9eKPVCeW4vlIpXRJjWLa1btg7U3PukW/fscK35Wyq5RAkSRsA8kDmMFDp+Qds069UxOWPE1Va/xT6N556/vA4ieJjvI3Lp0d9mfdPc3vl2C7lkRNpq3WzM3s1tc+fi3hJh682enDrO2aMP9Z0mF3ZNvv/++83HH3/cPH/+vHn58mXzxRdfZDmlvZzG6zTjdc159u/ynhN59uxZ88pXvrb/rHzD6ibgFbwh1X9PSRLlpT0v9hCnHLXnSPlRfjQHNAc0BzQHNAc0B6acA9dFLrmXzZF2LjHSqW3nEpO3l9OtTiB+7kchl2y307rZPBBKtsNpT8SBdNr2Hcpd8wvz3Odu1+Q777zT/PCHP2x+8pOfNJ9++mnzu9/9Tu9Nv9e9YMp7Qa1tzxWJXNJkPfmCJXJJC2TtIiZ9zSHNAc0BzQHNAc2BujlwKeQSvjZ3VJKvrW3Jg57kUokUYkRE751LD7GY3p74McLHyKWHnVaH/ndfjzPME1loH8jGHVGOUMJX6fbnEGXdDqe9jLDJv3IocqluTdM9YZ78iVwSoXRyQslf7CKX5rnw/RiorjHQHNAc0BzQHNAcuO45cAnk0hDiY0fKPO7o2dpwZI4nedJkkdMHKVQq9wSQI3vu7x9Jo308jBzb6rgdSPfl31zarMM54muENzdHX5G7v98067h7SmTS5GRSnL8il657TT7Xe3IVueSVVe/+zSHlSDnSHNAc0BzQHNAc0BzQHNAcWNocWCq5VCJlPOnjd/aU5IHvyRwjS7bkzE1zYz+O7cmbws4dvzsI9vZlBxljugcxe7LmgFjCV/aMYHr4PaXC1+J2O44Ov8aGXUiHRFiJLNr99tRBTrZxHdqMpIfaGKNpS7sm33jjjebtt99u3n333ebDDz9sPvroo4OfqFnaOqJ4dG/zc6D31+K8suqaTJoDmgOaA5oDmgOaA5oDmgOaA+c3B5ZILnkSo5Wc8URNtv6wu2hH+Ox2Cu1/5LpALvl4MvU2MqpINPWJH4SYI5/6kEtb2fXxj3vbubGdTplzlsx4hJPIpfNbR3XvOxwzkUt/f5gQTRDlQ3NAc0BzQHNAc0BzQHNAc+DS58AlkEuHu3XaXvL5jh0jW7Y7mEYil4pES8H+1n/hr9gd7KwiO51M1wirLWH08BtMjzuSyM4lI6S2u612xNqjrOVNO5eKY5cl/0aQE7mk+86533dS5JIJ6aMcaA5oDmgOaA5oDmgOaA5oDmgOXMYcWBS59LCraP+VsxLhslo1nhTJk0ttxNPuB7QPdhZVxFM6hwP7XUSE25nURXpwcimSRYFQOiKrCBnVFaP6R/9NJrsmv/rVrzbf+MY3mu985zvN06dPt389TmvuZay51zKOr3zlaw0+K1RUPiZFuVAuNAc0BzQHNAc0BzQHNAc0By5pDiyKXBpIVExGLi0gnoOdSy3xcHJp99fkQMSZTLR3gBV2VnURW+rvIC1bxo3lzq7Jf/mv/nXzb/7tv2tu/sOXm//4yn9p/vo//9f9i/olrT86l+u4n4pcckybJv11THqNs8ZZc0BzQHNAc0BzQHPg2ubApZBLpZ1C+99Tyrzgj0SutP3mUt94IhnEyAjDSuRSn78At1k//JB4JleSGX3HEsZW5JLuQ5d2HxK5JHJJ7LjmgOaA5oDmgOaA5oDmgObAhc+BSyCX8FKusrCD5uHrdUUCbrXaklO9vrIncknk0oWvjZdG8Mx5PiKXdLHoYVJzQHNAc0BzQHNAc0BzQHPgwueAyKUCISPyZDLyRCRg+5zTziXtXJqTCJrC9/8HVb3ez8rVDTwAAAAASUVORK5CYII=" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "![image.png](attachment:5aedfddd-56b6-4501-99cb-e878b3b24020.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "증권사를 통해서 데이터를 받게 되면 아래와 같은 이점을 기대할 수 있다.\n", - "\n", - "* 증권사는 주식 가격데이터의 관리에 관해서는 전문가이다. 충분히 신뢰할 수 있다고 생각한다.\n", - "* 수정주가 적용과 관련된 부분도 가장 합리적으로 수정주가를 계산해서 제공하고 있을 것으로 기대할 수 있다.\n", - "* 일봉 데이터 뿐만 아니라 다른 다양한 타임프레임의 데이터들도 모두 확인 가능하다.\n", - "\n", - "다만 위와 같은 방식은 아래와 같은 단점이 떠오른다.\n", - "\n", - "* 저걸 단순하게 있는 그대로 자동화 하기 위해서는 거의 자동 매크로와 같은 프로그램이 필요할 듯 하다.\n", - "\n", - "여기서 자연스럽게 다음 단계로 고려되는 것이 각 증권사에서 제공하는 OpenAPI 와 같은 기능들을 직접 사용하는 것이 되겠다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5. 증권사 API 를 활용해서 데이터를 가져와보자.\n", - "\n", - "맨 처음 시도해볼 증권사 API 를 고를 때, 참고할 자료들이 가장 풍부해 보이는 키움증권의 OpenAPI+ 를 먼저 사용해보기로 마음먹고 개발을 시작했다.\n", - "이후 이것저것 삽질하면서 개발을 하다 보니 결론적으로는 `koapy` 를 개발하게 되었다.\n", - "개발과정에서의 여러 삽질들은 여기서 설명하자면 너무 길어질듯해 나중에 기회가 되면 이야기를 풀어봤으면 한다.\n", - "\n", - "여기서는 `koapy` 를 사용해서 과거 일봉 데이터를 가져와 다른 데이터들과 한번 비교해본다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 키움증권의 OpenAPI+ 활용하기\n", - "\n", - "먼저 현재 환경이 32Bit 환경이 맞는지 확인을 하고 진행할 것이다." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "import platform\n", - "\n", - "assert platform.architecture()[0] == '32bit'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "로그인 처리와 관련해서는 이미 자동 로그인 설정이 되어있는 것이 좋지만,\n", - "그게 아니라면 이후 진행하면서 팝업되는 로그인 창에 수동으로 인증정보를 입력해 로그인을 진행한다.\n", - "\n", - "이제 아래처럼 `koapy` 를 사용해서 과거 일봉 데이터를 가져올 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "from koapy import KiwoomOpenApiPlusEntrypoint" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 16:58:13,444 [DEBUG] Testing if client is ready... - KiwoomOpenApiPlusEntrypoint.py:45\n", - "2022-01-14 16:58:23,475 [DEBUG] Client is not ready - KiwoomOpenApiPlusEntrypoint.py:47\n", - "2022-01-14 16:58:23,476 [DEBUG] Creating a new server... - KiwoomOpenApiPlusEntrypoint.py:48\n" - ] - } - ], - "source": [ - "kiwoom_entrypoint = KiwoomOpenApiPlusEntrypoint()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "kiwoom_entrypoint.EnsureConnected()" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 16:58:42,151 [DEBUG] Received 600 records from 2022-01-14 00:00:00 to 2019-08-13 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:58:42,457 [DEBUG] Received 600 records from 2019-08-12 00:00:00 to 2017-02-28 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:58:42,765 [DEBUG] Received 600 records from 2017-02-27 00:00:00 to 2014-09-24 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:58:43,052 [DEBUG] Received 600 records from 2014-09-23 00:00:00 to 2012-04-18 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:58:43,356 [DEBUG] Received 600 records from 2012-04-17 00:00:00 to 2009-11-20 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:00,170 [DEBUG] Received 600 records from 2009-11-19 00:00:00 to 2007-06-25 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:00,472 [DEBUG] Received 600 records from 2007-06-22 00:00:00 to 2005-01-24 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:00,749 [DEBUG] Received 554 records from 2005-01-21 00:00:00 to 2002-10-29 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n" - ] - } - ], - "source": [ - "kiwoom_data = kiwoom_entrypoint.GetDailyStockDataAsDataFrame(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드현재가거래량거래대금일자시가고가저가수정주가구분수정비율대업종구분소업종구분종목정보수정주가이벤트전일종가
003542034200050352017092920220114341000342500335500
134800067722623632320220113348000352000344000
2345500104771336405820220112339500352500339500
333500080508427227120220111336000344500334500
433500082861127647920220110339000339500329000
................................................
4749417006921652895220021104435004380040650
4750439007507873443320021101480004950042200
47514680013208806397920021031500005120045650
4752492508536384203020021030492504925048700
475344000205499042002102944000440004400080.00
\n", - "

4754 rows × 15 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 현재가 거래량 거래대금 일자 시가 고가 저가 \\\n", - "0 035420 342000 503520 170929 20220114 341000 342500 335500 \n", - "1 348000 677226 236323 20220113 348000 352000 344000 \n", - "2 345500 1047713 364058 20220112 339500 352500 339500 \n", - "3 335000 805084 272271 20220111 336000 344500 334500 \n", - "4 335000 828611 276479 20220110 339000 339500 329000 \n", - "... ... ... ... ... ... ... ... ... \n", - "4749 41700 692165 28952 20021104 43500 43800 40650 \n", - "4750 43900 750787 34433 20021101 48000 49500 42200 \n", - "4751 46800 1320880 63979 20021031 50000 51200 45650 \n", - "4752 49250 853638 42030 20021030 49250 49250 48700 \n", - "4753 44000 20549 904 20021029 44000 44000 44000 \n", - "\n", - " 수정주가구분 수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가 \n", - "0 \n", - "1 \n", - "2 \n", - "3 \n", - "4 \n", - "... ... ... ... ... ... ... ... \n", - "4749 \n", - "4750 \n", - "4751 \n", - "4752 \n", - "4753 8 0.00 \n", - "\n", - "[4754 rows x 15 columns]" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "kiwoom_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위의 주가는 수정주가가 적용되지 않은 결과이다. 이것을 앞서 KRX 에서 확인했던 데이터와 비교해보자." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "kiwoom_data_close = kiwoom_data.sort_values('일자')['현재가'].astype(int).to_numpy()\n", - "krx_data_close = krx_data.sort_index()['Close'].to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.sum(kiwoom_data_close - krx_data_close)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "차이가 없는 것이 확인된다. 긍정적인 결과이다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이번에는 수정주가를 확인해보자." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 16:59:01,131 [DEBUG] Received 600 records from 2022-01-14 00:00:00 to 2019-08-13 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:01,431 [DEBUG] Received 600 records from 2019-08-12 00:00:00 to 2017-02-28 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:18,182 [DEBUG] Received 600 records from 2017-02-27 00:00:00 to 2014-09-24 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:18,487 [DEBUG] Received 600 records from 2014-09-23 00:00:00 to 2012-04-18 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:18,781 [DEBUG] Received 600 records from 2012-04-17 00:00:00 to 2009-11-20 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:19,159 [DEBUG] Received 600 records from 2009-11-19 00:00:00 to 2007-06-25 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:19,455 [DEBUG] Received 600 records from 2007-06-22 00:00:00 to 2005-01-24 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 16:59:36,162 [DEBUG] Received 554 records from 2005-01-21 00:00:00 to 2002-10-29 00:00:00 for code 035420 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n" - ] - } - ], - "source": [ - "kiwoom_data_adjusted = kiwoom_entrypoint.GetDailyStockDataAsDataFrame(code, adjusted_price=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드현재가거래량거래대금일자시가고가저가수정주가구분수정비율대업종구분소업종구분종목정보수정주가이벤트전일종가
003542034200050352017092920220114341000342500335500
134800067722623632320220113348000352000344000
2345500104771336405820220112339500352500339500
333500080508427227120220111336000344500334500
433500082861127647920220110339000339500329000
................................................
47491389207857362895220021104144914591354
47501462225461563443320021101159816481405
47511558396660666397920021031166517051520
47521640256347754203020021030164016401622
475314656170879042002102914651465146580.00
\n", - "

4754 rows × 15 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 현재가 거래량 거래대금 일자 시가 고가 저가 \\\n", - "0 035420 342000 503520 170929 20220114 341000 342500 335500 \n", - "1 348000 677226 236323 20220113 348000 352000 344000 \n", - "2 345500 1047713 364058 20220112 339500 352500 339500 \n", - "3 335000 805084 272271 20220111 336000 344500 334500 \n", - "4 335000 828611 276479 20220110 339000 339500 329000 \n", - "... ... ... ... ... ... ... ... ... \n", - "4749 1389 20785736 28952 20021104 1449 1459 1354 \n", - "4750 1462 22546156 34433 20021101 1598 1648 1405 \n", - "4751 1558 39666066 63979 20021031 1665 1705 1520 \n", - "4752 1640 25634775 42030 20021030 1640 1640 1622 \n", - "4753 1465 617087 904 20021029 1465 1465 1465 \n", - "\n", - " 수정주가구분 수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가 \n", - "0 \n", - "1 \n", - "2 \n", - "3 \n", - "4 \n", - "... ... ... ... ... ... ... ... \n", - "4749 \n", - "4750 \n", - "4751 \n", - "4752 \n", - "4753 8 0.00 \n", - "\n", - "[4754 rows x 15 columns]" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "kiwoom_data_adjusted" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "맨 처음의 `FinancialDataReader` 가 네이버 금융의 데이터를 가져오고 있고, 해당 데이터는 수정주가가 적용된 데이터이다. 해당 데이터와 값을 비교해보자" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "kiwoom_data_adjusted_close = kiwoom_data_adjusted.sort_values('일자')['현재가'].astype(int).to_numpy()\n", - "fdr_data_adjusted_close = fdr_data.sort_index()['Close'].to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-44276961" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.sum(kiwoom_data_adjusted_close - fdr_data_adjusted_close)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-9313.622423222549" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.mean(kiwoom_data_adjusted_close - fdr_data_adjusted_close)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "꽤나 차이가 발생하는 것을 확인할 수 있으며, 이것은 각 데이터 출처에서 수정주가를 계산하는 방식이 다른 것으로 인한 차이이지 않을까 추측해볼 수 있다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "좀 더 시각적으로 확인해보자면 아래처럼 해볼 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(fdr_data.index, kiwoom_data_adjusted_close)\n", - "plt.plot(fdr_data.index, fdr_data_adjusted_close)\n", - "\n", - "plt.legend(['kiwoom', 'fdr'])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "대략 2013년과 2014년 사이에 뭔 일이 있었는지 급격한 가격변화가 있었고, 해당 시점에서 부터 두 데이터의 가격 차이가 발생하는 것으로 보인다.\n", - "\n", - "사실 해당 시점은 현재 NAVER 의 전신인 당시의 NHN 이 2013.08.01 을 기점으로 NAVER 와 NHN엔터테인먼트 (현재의 NHN) 으로 기업분할을 한 시점이다.\n", - "여기서 유추해볼 수 있는건 네이버와 키움증권이 해당 이벤트를 전후해서 수정주가 처리를 다른 방식으로 하고 있다는 것이다.\n", - "어느 방식이 더 적절한지에 대해서는 당장은 알 수 없기 때문에 제삼자의 케이스를 추가로 확인해보는게 좋겠다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "내가 알고 있는 것 처럼 `FinancialDataReader` 의 데이터가 수정주가가 아닐 수도 있을 것 같아서 원래 키움증권의 데이터와도 비교해봤다." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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SPv06YPvvvsOr7zyCl566SW0atUKv/32m//UGCEiIiK3cqoCq6f5TAVWIiIispu9n9+sgkVERERexWCEiIiIvIrBCBEREXkVgxEiIiLyKgYjRERE5FUMRoiIiMirGIwQERGRVzEYISIiIq/yyVV7zRnqsuXn53u5JURERGQvw+d2dfVV/SIYKSgoAAAkJSV5uSVERETkqIKCAkRGRlo97hfl4PV6Pc6dO4fw8HCoVCpvN8dp+fn5SEpKwunTp1nW3oP4vnsH33fP43vuHXzfrRMEAQUFBWjYsKFs3TpzftEzolar0bhxY283w2UiIiL4DesFfN+9g++75/E99w6+78ps9YgYMIGViIiIvIrBCBEREXkVgxEPCgoKwtSpUxEUFOTtptQpfN+9g++75/E99w6+7zXnFwmsREREVHuxZ4SIiIi8isEIEREReRWDESIiIvIqBiNERETkVQxGHDB9+nT07NkT4eHhiIuLw80334yDBw/KziktLcWECRPQoEEDhIWF4bbbbkN2drbsnFOnTuGGG25AaGgo4uLi8Nxzz6GyslLxOdevX4+AgAB06dLFXS/L53nyfV+0aBE6d+6M0NBQJCYm4oEHHsDFixfd/hp9kave9yeeeALdu3dHUFCQ4vdxRkYGbrrpJiQmJqJevXro0qULFi1a5M6X5tM89b4DYnXM999/H61bt0ZQUBAaNWqEadOmueul+TRXvO+7du3C3XffjaSkJISEhKBt27b46KOPLJ4rIyMD3bp1Q1BQEFq2bIn58+e7++X5PoHsNmTIEGHevHnCnj17hJ07dwrDhg0TmjRpIhQWFhrPGTdunJCUlCSkp6cLW7duFXr37i306dPHeLyyslLo0KGDMGjQIGHHjh3CihUrhJiYGGHy5MkWz3f58mWhefPmwuDBg4XOnTt74iX6JE+97+vWrRPUarXw0UcfCceOHRP+/fdfoX379sItt9zi0dfrK1zxvguCIDz++OPCp59+Ktx3332K38fTpk0TXnnlFWH9+vXCkSNHhJkzZwpqtVr4448/3P0SfZKn3nfDOSkpKcLvv/8uHDt2TNi6davw119/ufPl+SxXvO9z5swRnnjiCSEjI0M4evSo8M033wghISHCJ598Yjzn2LFjQmhoqDBp0iRh3759wieffCJoNBph5cqVHn29vobBSA3k5OQIAIS1a9cKgiAI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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(fdr_data.index, kiwoom_data_close)\n", - "plt.plot(fdr_data.index, fdr_data_adjusted_close)\n", - "\n", - "plt.legend(['kiwoom', 'fdr'])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "꽤나 차이가 크다. 이상하게 2007년부터 2009년 정도까지는 가격이 또 겹치는 구간이 있는거 같은데 뭘까.. 내가 보기에는 원래 수정주가가 최근부터 가장 오래된 시점까지 쭉 이어져서 수정되어야 하지만 여기서는 2009년에 한번 뚝 끊고 다시 거기서부터 수정주가를 적용한듯한 느낌도 든다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 대신증권의 Cybos Plus 활용해보기\n", - "\n", - "여기서는 대신증권의 Cybos Plus 를 활용해 수정주가를 가져와 추가적으로 확인해보자." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "대신증권 Cybos Plus 의 경우도 마찬가지로 32Bit 환경에서만 사용이 가능하다." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "import platform\n", - "\n", - "assert platform.architecture()[0] == '32bit'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "앞의 키움증권 케이스와는 다르게 여기서는 자동 로그인과 같은 설정은 따로 없다.\n", - "대신에 Cybos Plus 프로그램을 미리 실행 및 로그인까지 진행해두는 것이 필요하다.\n", - "미리 실행시켜두지 않았다면 지금 실행하자." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이제 아래처럼 `koapy` 를 사용해서 과거 일봉 데이터를 가져올 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "from koapy import CybosPlusEntrypoint" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "cybos_entrypoint = CybosPlusEntrypoint()" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:00:52,672 [INFO] Succesfully connected to CYBOS Plus - CybosPlusEntrypointMixin.py:227\n" - ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cybos_entrypoint.EnsureConnected()" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:00:52,727 [DEBUG] Requesting from 2022-01-14 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:52,777 [DEBUG] Requested 2222, received 2221 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:52,830 [DEBUG] Received data from 2022-01-14 00:00:00+09:00 to 2013-01-08 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:52,831 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:52,835 [DEBUG] Trailing rows truncated: 1 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:52,836 [DEBUG] Requesting from 2013-01-08 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:52,882 [DEBUG] Requested 2222, received 2221 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:52,936 [DEBUG] Received data from 2013-01-08 00:00:00+09:00 to 2004-02-09 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:52,936 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:52,941 [DEBUG] Trailing rows truncated: 1 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:52,941 [DEBUG] Requesting from 2004-02-09 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:52,976 [DEBUG] Requested 2222, received 314 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:52,985 [DEBUG] Received data from 2004-02-09 00:00:00+09:00 to 2002-10-29 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:52,985 [DEBUG] No more data to request - CybosPlusEntrypointMixin.py:454\n" - ] - } - ], - "source": [ - "cybos_data_adjusted = cybos_entrypoint.GetDailyStockDataAsDataFrame(code, adjusted_price=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
날짜시가고가저가종가거래량거래대금수정주가일자수정주가비율
02022011434100034250033550034200050425017117900000020220114100.00
12022011334800035200034400034800067722623632300000020220113100.00
220220112339500352500339500345500104771336405800000020220112100.00
32022011133600034450033450033500080508427227100000020220111100.00
42022011033900033950032900033500082861127647900000020220110100.00
..............................
47492002110422832298213321881319022128952000000200211045.24
47502002110125192598221423041430685434432000000200211015.24
47512002103126242687239624562517131063979000000200210315.24
47522002103025842584255625841626732742030000000200210305.24
4753200210292309230923092309391591904000000200210295.24
\n", - "

4754 rows × 9 columns

\n", - "
" - ], - "text/plain": [ - " 날짜 시가 고가 저가 종가 거래량 거래대금 \\\n", - "0 20220114 341000 342500 335500 342000 504250 171179000000 \n", - "1 20220113 348000 352000 344000 348000 677226 236323000000 \n", - "2 20220112 339500 352500 339500 345500 1047713 364058000000 \n", - "3 20220111 336000 344500 334500 335000 805084 272271000000 \n", - "4 20220110 339000 339500 329000 335000 828611 276479000000 \n", - "... ... ... ... ... ... ... ... \n", - "4749 20021104 2283 2298 2133 2188 13190221 28952000000 \n", - "4750 20021101 2519 2598 2214 2304 14306854 34432000000 \n", - "4751 20021031 2624 2687 2396 2456 25171310 63979000000 \n", - "4752 20021030 2584 2584 2556 2584 16267327 42030000000 \n", - "4753 20021029 2309 2309 2309 2309 391591 904000000 \n", - "\n", - " 수정주가일자 수정주가비율 \n", - "0 20220114 100.00 \n", - "1 20220113 100.00 \n", - "2 20220112 100.00 \n", - "3 20220111 100.00 \n", - "4 20220110 100.00 \n", - "... ... ... \n", - "4749 20021104 5.24 \n", - "4750 20021101 5.24 \n", - "4751 20021031 5.24 \n", - "4752 20021030 5.24 \n", - "4753 20021029 5.24 \n", - "\n", - "[4754 rows x 9 columns]" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cybos_data_adjusted" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "앞서 시각적으로 확인해 봤던 결과에서 위의 케이스를 추가해보자." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [ - "cybos_data_adjusted_close = cybos_data_adjusted.sort_values('날짜')['종가'].astype(int).to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAGdCAYAAAD+JxxnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAA9hAAAPYQGoP6dpAABz00lEQVR4nO3dd3QUVRsG8Gd7ekJNKAm9dwKEANIhICoIKAJKkSIIKEWaIthRUREpYiWoIEVFPopgBALSIfQuNbQktBRSts73xyaTTHY32dTdZJ/fOTnO3Lkz++4i2ZdbZYIgCCAiIiJyQXJHB0BERETkKEyEiIiIyGUxESIiIiKXxUSIiIiIXBYTISIiInJZTISIiIjIZTERIiIiIpfFRIiIiIhcltLRATgzk8mEO3fuwNvbGzKZzNHhEBERkR0EQUBSUhIqV64MuTznNh8mQjm4c+cOAgMDHR0GERER5cPNmzdRtWrVHOswEcqBt7c3APMH6ePj4+BoiIiIyB6JiYkIDAwUv8dzwkQoBxndYT4+PkyEiIiIShh7hrVwsDQRERG5LCZCRERE5LKYCBEREZHL4hihAhIEAQaDAUaj0dGhUDqFQgGlUsklD4iIKFdMhApAp9Ph7t27SElJcXQolI2HhwcqVaoEtVrt6FCIiMiJMRHKJ5PJhGvXrkGhUKBy5cpQq9VsgXACgiBAp9Ph3r17uHbtGurUqZPrYlpEROS6mAjlk06ng8lkQmBgIDw8PBwdDmXh7u4OlUqFGzduQKfTwc3NzdEhERGRk+I/lQuIrQ3OiX8uRERkD35bEBERkctiIkREREQui4mQC+rcuTMmT55s9dqIESPQr1+/Yo2HiIjIUThYmiQWLVoEQRAcHQYREVGxYIsQSfj6+sLPz8/RYRARUQl35vIhzF35PG7e/c/RoeSIiVAhEgQBKTqDQ34K0oqzZcsW+Pr6YtWqVZKusc2bN8PPz09cNfvEiROQyWSYNWuWeO/o0aPx4osviue///47GjVqBI1Gg+rVq+Pzzz+XvNajR48wbNgwlClTBh4eHujduzf++y/zL0l4eDj8/PywefNm1KtXDx4eHhg4cCBSUlKwcuVKVK9eHWXKlMFrr73G1byJiJzQo4R7MBmNeG33y9iA85i/aZSjQ8oRu8YKUareiIZztzvktc+9FwYPdd7/OFevXo1x48Zh9erVeOqppxARESFee+KJJ5CUlITjx4+jVatW2L17N8qXL4/IyEixzu7duzFz5kwAQFRUFJ5//nm88847GDRoEPbv349XX30V5cqVw4gRIwCYxyD9999/+N///gcfHx/MnDkTTz75JM6dOweVSgUASElJwVdffYU1a9YgKSkJ/fv3x7PPPgs/Pz9s3boVV69exYABA9C+fXsMGjQo/x8aEREVqlXbPsVnMT8hRFcG9zTmtpbrsocOjipnTIRc2NKlS/HWW29h06ZN6NSpk8V1X19fNG/eHJGRkWjVqhUiIyMxZcoUvPvuu3j8+DESEhJw+fJl8d4vvvgC3bp1w9tvvw0AqFu3Ls6dO4cFCxZIEqB9+/ahXbt2AIBVq1YhMDAQf/75J5577jkAgF6vx9dff41atWoBAAYOHIiff/4ZsbGx8PLyQsOGDdGlSxfs2rWLiRARkRPZfmM9DG4y7NPEi2Vqwbk7n5gIFSJ3lQLn3gtz2GvnxW+//Ya4uDjs27cPrVu3tlmvU6dOiIyMxLRp0/Dvv/9i/vz5WLduHfbu3YuHDx+icuXKqFOnDgDg/Pnz6Nu3r+T+9u3b48svv4TRaMT58+ehVCoREhIiXi9Xrhzq1auH8+fPi2UeHh5iEgQA/v7+qF69Ory8vCRlcXFxeXrPRERUtI67pTk6hDxjIlSIZDJZvrqnHKFFixY4duwYfvzxR7Rq1crmPmmdO3fGjz/+iJMnT0KlUqF+/fro3LkzIiMj8ejRI6stSQWV0UWWQSaTWS0zmUyF/tpERJQ/JlvjNp18G07nbq+iIlOrVi3s2rULGzduxKRJk2zWyxgntHDhQjHpyUiEIiMj0blzZ7FugwYNsG/fPsn9+/btQ926daFQKNCgQQMYDAYcOnRIvP7gwQNcvHgRDRs2LNw3SERExcpgNFi/4OQrsjARcmF169bFrl278Pvvv9tcYLFMmTJo2rQpVq1aJSY9HTt2xLFjx3Dp0iVJi9C0adOwY8cOvP/++7h06RJWrlyJJUuW4I033gAA1KlTB3379sWYMWOwd+9enDx5Ei+++CKqVKli0aVGREQli96gs1pulDl3JlQy+nGoyNSrVw87d+5E586doVBYH2fUqVMnnDhxQkyEypYti4YNGyI2Nhb16tUT67Vs2RLr1q3D3Llz8f7776NSpUp47733xBljALBixQq8/vrreOqpp6DT6dCxY0ds3brVouuLiIhKFoNJb7X8urqYA8kjmcBlhG1KTEyEr68vEhIS4OPjI7mWlpaGa9euoUaNGnBzc3NQhGQL/3yIiIrXo4R76PhnV6vXTg8/Xayx5PT9nR27xoiIiKjAbLUI1dU6d6rh3NERERFRiWBrtX9POHffGBMhIiIiKjCDycb0eScfgMNEiIiIiArMaGPWmNzJFxJiIkREREQFZjRaHyPk7JgIERERUYHZ6hqTsUWIiIiISjuBiRARERG5KtstQs6NiZALEgQBY8eORdmyZSGTyXDixAmLOp07d7a57QYREVF2RpP1vcZsbertLLjFhgvatm0bwsPDERkZiZo1a6J8+fKODomIiEo4g63B0k4+fZ6JkAu6cuUKKlWqhHbt2uX7GTqdDmq1cy+SRURExcdkY0FFZ28RYteYixkxYgQmTZqE6OhoyGQyVK9eHcnJyRg2bBi8vLxQqVIlfP755xb3Va9eHe+//z6GDRsGHx8fjB071gHRExGRszLZ6BpTwPqG3s6CLUKFSRAAfYpjXlvlAdiRdS9atAi1atXCt99+iyNHjkChUGD69OnYvXs3Nm7ciIoVK+LNN9/EsWPH0Lx5c8m9n332GebOnYt58+YV0ZsgIqKSyiiYEyFvowlJisx2FmdfUJGJUGHSpwAfVXbMa795B1B75lrN19cX3t7eUCgUCAgIwOPHj/HDDz/gl19+Qbdu3QAAK1euRNWqVS3u7dq1K6ZNm1booRMRUcm2/+RfmHB8OiCznCwvOPkgIXaNubgrV65Ap9MhJCRELCtbtizq1atnUbdVq1bFGRoREZUQXxyaBUN6r0SiQppaOHcaxBahwqXyMLfMOOq1i5inZ+4tTkRE5Hp0MpPkvI5Whv80zp4CmTERKkwymV3dU86kVq1aUKlUOHToEIKCggAAjx49wqVLl9CpUycHR0dERCWBUpAha9tPB9+O+C9td/qZcydE7BpzcV5eXhg1ahSmT5+OnTt34syZMxgxYgTkcv6vQURE9sk+IHpc30/E44w06N6jO/hi7URcu32hGCPLHVuECAsWLMDjx4/x9NNPw9vbG9OmTUNCQoKjwyIiohLKw80TA2WN8JtwVhws/fb6QdiniceeLXvw59hTDo4wExMhFzR58mTJ9hleXl74+eef8fPPP4tl06dPl9xz/fr1YoqOiIhKGusbq0rL9mniAQBXnGzsEPs/iIiIqEj9tmOpo0OwiYkQERERFYi1tYIyWokECNh5ZW1xh2Q3JkJERERUIFnTII0p/SzLbgcmJ545xkSIiIiICiRromNMz38StA8AAAc1SeL4oAz/HvtfcYWWKyZCREREVCDKLOlEc615Pb0dyls2638eNafIY7IXEyEiIiIqkIoyX/H4vWd+AQCoBdvdYanZVqJ2JCZCREREVCD+miricWClOgAAtxyGBd1ROc+O9AVKhD7++GPIZDLJmjRpaWmYMGECypUrBy8vLwwYMACxsbGS+6Kjo9GnTx94eHigYsWKmD59OgwGg6ROZGQkWrZsCY1Gg9q1ayM8PNzi9ZcuXYrq1avDzc0NISEhOHz4sOS6PbEQERGR/ZJTkizKMmaNhWp9xDKF846Plsh3InTkyBF88803aNq0qaR8ypQp2LRpE9avX4/du3fjzp076N+/v3jdaDSiT58+0Ol02L9/P1auXInw8HDMnTtXrHPt2jX06dMHXbp0wYkTJzB58mSMHj0a27dvF+usXbsWU6dOxbx583Ds2DE0a9YMYWFhiIuLszsWIiIist/8VSPQbl0o1vy9MNe6pToRevz4MYYOHYrvvvsOZcqUEcsTEhLwww8/4IsvvkDXrl0RHByMFStWYP/+/Th48CAA4O+//8a5c+fwyy+/oHnz5ujduzfef/99LF26FDqdDgCwfPly1KhRA59//jkaNGiAiRMnYuDAgVi4MPOD/+KLLzBmzBiMHDkSDRs2xPLly+Hh4YEff/zR7lgo76pXr44vv/zS0WEQEZEDrDZEwSSTYfnN77NdMWc9WVeYVlhdbTpTSlpyYYeXL/lKhCZMmIA+ffqge/fukvKoqCjo9XpJef369REUFIQDBw4AAA4cOIAmTZrA399frBMWFobExEScPXtWrJP92WFhYeIzdDodoqKiJHXkcjm6d+8u1rEnFiIiIsq7lGzZQ8a46KypT24JxvodXxZiRPmX573G1qxZg2PHjuHIkSMW12JiYqBWq+Hn5ycp9/f3R0xMjFgnaxKUcT3jWk51EhMTkZqaikePHsFoNFqtc+HCBbtjyU6r1UKr1YrniYmJVusRERG5mvd+GiIep8pzb0dRCjm3CO26tRHD8VaB4yqoPLUI3bx5E6+//jpWrVoFNze3oorJYebPnw9fX1/xJzAw0NEhFQmTyYRPP/0UtWvXhkajQVBQED788EN07doVEydOlNS9d+8e1Go1duzYIZYlJSVh8ODB8PT0RJUqVbB0qXQPmejoaPTt2xdeXl7w8fHB888/LxmkfvLkSXTp0gXe3t7w8fFBcHAwjh49WrRvmoiI8m3v8c1YL5y2ef0fo/nafWQOpG7n0cqiXj1tZtoR5ZZaiBHmX54SoaioKMTFxaFly5ZQKpVQKpXYvXs3vvrqKyiVSvj7+0On0yE+Pl5yX2xsLAICAgAAAQEBFjO3Ms5zq+Pj4wN3d3eUL18eCoXCap2sz8gtluxmz56NhIQE8efmzZv2fzgABEFAij7FIT9CDus1WHufH3/8Md5++22cO3cOq1evhr+/P0aPHo3Vq1dLWsV++eUXVKlSBV27dhXLFixYgGbNmuH48eOYNWsWXn/9dURERAAwJ1l9+/bFw4cPsXv3bkRERODq1asYNGiQeP/QoUNRtWpVHDlyBFFRUZg1axZUKlWePmsiIio+S468neP1BIU5nbioyVwfaPqgbzFEGSypl/W6s8hT11i3bt1w+rQ0Ixw5ciTq16+PmTNnIjAwECqVCjt27MCAAQMAABcvXkR0dDRCQ0MBAKGhofjwww8RFxeHihUrAgAiIiLg4+ODhg0binW2bt0qeZ2IiAjxGWq1GsHBwdixYwf69esHwPwFvGPHDrFFIzg4ONdYstNoNNBoNHn5SCRSDakIWR2S7/sL4tCQQ/BQeeRaLykpCYsWLcKSJUswfPhwAECtWrXQoUMHpKWlYeLEidi4cSOef/55AEB4eDhGjBgBWZY9Y9q3b49Zs2YBAOrWrYt9+/Zh4cKF6NGjB3bs2IHTp0/j2rVrYovaTz/9hEaNGuHIkSNo3bo1oqOjMX36dNSvXx8AUKdOnUL9LIiIqHDlZ68wpVKF4JphWH0pqggiKjx5ahHy9vZG48aNJT+enp4oV64cGjduDF9fX4waNQpTp07Frl27EBUVhZEjRyI0NBRt27YFAPTs2RMNGzbESy+9hJMnT2L79u2YM2cOJkyYICYh48aNw9WrVzFjxgxcuHABy5Ytw7p16zBlyhQxlqlTp+K7777DypUrcf78eYwfPx7JyckYOXIkANgViys6f/48tFotunXrZnHNzc0NL730kjjz7tixYzhz5gxGjBghqZc9kQwNDcX58+fF5wcGBkq6FRs2bAg/Pz+xztSpUzF69Gh0794dH3/8Ma5cuVKYb5GIiArZeY0xX/cpFc7f2p/nwdK5WbhwIeRyOQYMGACtVouwsDAsW7ZMvK5QKLB582aMHz8eoaGh8PT0xPDhw/Hee++JdWrUqIEtW7ZgypQpWLRoEapWrYrvv/8eYWFhYp1Bgwbh3r17mDt3LmJiYtC8eXNs27ZNMoA6t1gKm7vSHYeGHCqy5+f22nbVc8+53ujRo9G8eXPcunULK1asQNeuXVGtWrXCCFH0zjvvYMiQIdiyZQv++usvzJs3D2vWrMGzzz5bqK9DRERF58TFvWher0OOdeRyheR8ABrhd5wtyrDyTCbkZXCJi0lMTISvry8SEhLg4+MjuZaWloZr166hRo0aJWrgeFpaGsqWLYuvvvoKo0ePtlonJCQEvXr1wpIlS7BkyRIMHjxYvFa9enU0bNhQ0nU5ePBgJCQkYOvWrYiIiEDv3r0lXWPnzp0Tu8ZatbIcPDd48GAkJyfjf/8rvN2IS+qfDxGRM2qysonV8oGyxpg37FfJ9dPDM4fQ7D2+GeNPzRbPn5M3xXrTKat1C1NO39/Zca8xF+Pm5oaZM2dixowZ+Omnn3DlyhUcPHgQP/zwg1hn9OjR+PjjjyEIgtVWmn379uHTTz/FpUuXsHTpUqxfvx6vv/46AKB79+5o0qQJhg4dimPHjuHw4cMYNmwYOnXqhFatWiE1NRUTJ05EZGQkbty4gX379uHIkSNo0KBBsX0GRERUOH4TzuR4XaEo9I6nQuf8EVKhe/vtt6FUKjF37lzcuXMHlSpVwrhx48TrgwcPxuTJkzF48GCrrSnTpk3D0aNH8e6778LHxwdffPGF2G0pk8mwceNGTJo0CR07doRcLkevXr2wePFiAOau0QcPHmDYsGGIjY1F+fLl0b9/f7z77rvF8+aJiKjQuJmknUrPor7kPPsYIYXM+dIO54uIipxcLsdbb72Ft96yvpDV/fv3kZaWhlGjRllcu379eq7PDwoKwsaNG61eU6vV+PXXX/MULxEROaeGOum4026NX5Sc33t0W3LupfEDUszHapNzjMxh1xiJ9Ho9YmJiMGfOHLRt2xYtW7Z0dEhEROTE5OlphKfJvD6Qu9pTcr12oHRjdh/38uKxXgaYjPmbjVaYmAiRaN++fahUqRKOHDmC5cuXOzocIiJyEjV01svlMnMaYUjfZcxNI13PrkqFWpJzpTyzq0yQyTBtRe9CjDJ/2DVGos6dO+dphWoiInINttaDlqcnQPr0NXezJ0IqpVpynnVxXgD4R3W3UOIrCLYIERERUY5srSxtEkzQ6bQwpSc42bvGlNlmjWVPhJwBEyEiIiLKkcFG/nLYLRkp2syNVt3cpImQXCFdULG8b9VCj62gmAgVELuSnBP/XIiICo9RZvt3atLjR+Kxh8Y7x+eEhQ7BM6bahRZXYWAilE8Zu6WnpKQ4OBKyJuPPhbvaExEVnCGHa4kpCeKxuyb3zb8/HLmhECIqPBwsnU8KhQJ+fn6Ii4sDAHh4eDhl36erEQQBKSkpiIuLg5+fHxTZmmWJiCjvbHWNAUBySjwAQCkIFl1h9ohPug8/7/K5VywiTIQKICAgAADEZIich5+fn/jnQ0REBZNjIpRmbhFS5XNIwuXoM2jVqHO+7i0MTIQKQCaToVKlSqhYsSL0er2jw6F0KpWKLUFERIUopxTnfoJ5CnyqPH+jbQwmG4sUFRMmQoVAoVDwi5eIiEotHyOQaiPP+efqGkCT/2cbjDmNQCp6HCxNRERENsXcv4lYle10oa5Pkzw/861KI8VjwcREiIiIiJzU+xtetChbUGcW5OljgpQK8+rR1Wz0cGVsrtrbWE0se6HnVJQxmterNpocu98YEyEiIiKy6ToeWpT1ajdUTCCM6S06tsZT/9BuOUa5d8Z7Q9dJyjOWJnJ01xjHCBEREVGeKQTzbLI/kiMBhRzJcus7kjWv1wHN63WwKM9InEzsGiMiIqKSRpE+lyxBYU4l7inzllJk1DYJtrZ0LR5MhIiIiCjPUvI5XT6DPL1rzGhy7PIzTISIiIjIJkMO+4wVhCy9c4yDpYmIiMhp3VEVzfZRGQmIwESIiIiISop62sJJHTLSK4ODB0tz1hgRERHZ5ee2X6NhjdaF8qzMWWMcLE1EREQlQKB/bajV5v00njLWKNCz5ELGGCEOliYiIiIn1VVXUTwu411BPH6i7kBJvVZpHnl6rtgixOnzRERE5Kx2quMAAI20SsizbDCuUEhH13w2aGOenpuRCAkCB0sTERGRkzurkQ5qVshV4nGI1gvl/ALy9LzsW3Q4ChMhIiIiyjNllhah6u6183x/xjpCJrYIERERUUmjkGd2kymztA7ZK2NlaZOpaBZstDsOh746ERERlUgKRWbyo1So83x/ZosQu8aIiIjICRkMtqe2Z20Fyk+LUIrc3CW28+7mvAdWiJgIERERkVUJjx/YvKaUtAhp8vzsW+lbd5x24zpCRERE5IQeJMTZvJZ1Kr0qHy1CzoKJEBEREVmV8PiezWtZW4RUSrfiCKdIMBEiIiIiq5KSH9m8psoyQNrXs4LNes6OiRARERFZZTRlrvHT2xAkuZZ11lj9am2KLabCxkSIiIjIRZ2/GoWk5Hib14Us+4BN7bvcZj13tXthhlWsmAgRERG5oL3HN+P5f0fguV872KwjwLzYYXmDCQHlAyXXsm6WKsuyuGJJw0SIiIjIBS07PBcAcFsls1lHEMyJkO0aZsoSnAgpc69CREREpY096/dk7RrLrnbVRmiepoFMJkOVijULM7RixUSIiIiIrMrYENVai5BcocDPrxzN97Nr6oCred+Zo9Cxa4yIiIisMpnMLUKyItgX9e12i9EkTYXZASMK/+F5wBYhIiIisipjsHRRaNWoM1Y3OlZkz7cXW4SIiIjIqszB0rkNly65mAgRERGRdemDpUtvGsREiIiIiGzIaBEqzZgIERERkVUZY4TYIkREREQux5TDOkKlBRMhIiIissrelaVLMiZCRERELuar9ZMl5waD9VWmmQgRERFRqRL74Da+S9khKdMZdFbrmgQDgKJZUNFZMBEiIiJyIfGJcRZlOn2q1bpGk3mLDXkpbhNiIkRERORC9EbL1h+9jRahizGHAQC6UtwkxESIiIjIhVjrBtPqrSdCf+AcAOCuii1CREREVAoY9FqLMqONFiFXwESIiIjIhegMaRZlWn2KAyJxDkyEiIiIXEiaznJgtM5KK5GrYCJERETkQqzNEFu4c7JFWVJyfNEH4wSYCBEREbkQa4nQYc1ji7Irt84URzgOx0SIiIjIhegM9nWDebh5FXEkzoGJEBERkQvRGy0HS1sjmErv2kFZMREiIiJyIfa2CLkKJkJEREQuxFaL0IvftILJaBTPTYKpuEJyqDwlQl9//TWaNm0KHx8f+Pj4IDQ0FH/99Zd4PS0tDRMmTEC5cuXg5eWFAQMGIDY2VvKM6Oho9OnTBx4eHqhYsSKmT58Og8EgqRMZGYmWLVtCo9Ggdu3aCA8Pt4hl6dKlqF69Otzc3BASEoLDhw9LrtsTCxERkauxtsUGAJx00+JefIx4bhLYNWahatWq+PjjjxEVFYWjR4+ia9eu6Nu3L86ePQsAmDJlCjZt2oT169dj9+7duHPnDvr37y/ebzQa0adPH+h0Ouzfvx8rV65EeHg45s6dK9a5du0a+vTpgy5duuDEiROYPHkyRo8eje3bt4t11q5di6lTp2LevHk4duwYmjVrhrCwMMTFZW4kl1ssRERErkif3jVWX6uwuGY0ZTZMCILR4nppJBOEgqV8ZcuWxYIFCzBw4EBUqFABq1evxsCBAwEAFy5cQIMGDXDgwAG0bdsWf/31F5566incuXMH/v7+AIDly5dj5syZuHfvHtRqNWbOnIktW7bgzJnMaXsvvPAC4uPjsW3bNgBASEgIWrdujSVLlgAATCYTAgMDMWnSJMyaNQsJCQm5xmKPxMRE+Pr6IiEhAT4+PgX5mIiIiJzCZ2vGYaV2H1qkuaGeZyOsMUaJ18oaTKhp8MKKVw7h1H8HMXT/GPHa6eGnHRFuvuTl+zvfY4SMRiPWrFmD5ORkhIaGIioqCnq9Ht27dxfr1K9fH0FBQThw4AAA4MCBA2jSpImYBAFAWFgYEhMTxValAwcOSJ6RUSfjGTqdDlFRUZI6crkc3bt3F+vYE4s1Wq0WiYmJkh8iIqLSIvLoBux4vBcAoIAcFbwDJdcfKuU46pYCnU4LZBkjVFvLTVdFp0+fhpeXFzQaDcaNG4cNGzagYcOGiImJgVqthp+fn6S+v78/YmLMfY4xMTGSJCjjesa1nOokJiYiNTUV9+/fh9FotFon6zNyi8Wa+fPnw9fXV/wJDAy0WZeIiKikmXR2Lm6l7ySvgBwqhdpqveiY/ySDpb96+vdiic8R8pwI1atXDydOnMChQ4cwfvx4DB8+HOfOnSuK2Ird7NmzkZCQIP7cvHnT0SEREREVCaVMAY3Kzeq1e/G3xMHSGpOAwEp1ijO0YqXM6w1qtRq1a9cGAAQHB+PIkSNYtGgRBg0aBJ1Oh/j4eElLTGxsLAICAgAAAQEBFrO7MmZyZa2TfXZXbGwsfHx84O7uDoVCAYVCYbVO1mfkFos1Go0GGo0mD58GERFRyaSQKeCp8bV6zWg0ACZzi1Dp7RQzK/A6QiaTCVqtFsHBwVCpVNixY4d47eLFi4iOjkZoaCgAIDQ0FKdPn5bM7oqIiICPjw8aNmwo1sn6jIw6Gc9Qq9UIDg6W1DGZTNixY4dYx55YiIiIXJkCCni6l7F6be6xmfjziHlCkgylexp9nlqEZs+ejd69eyMoKAhJSUlYvXo1IiMjsX37dvj6+mLUqFGYOnUqypYtCx8fH0yaNAmhoaHiLK2ePXuiYcOGeOmll/Dpp58iJiYGc+bMwYQJE8SWmHHjxmHJkiWYMWMGXn75ZezcuRPr1q3Dli1bxDimTp2K4cOHo1WrVmjTpg2+/PJLJCcnY+TIkQBgVyxERESuTCFTwsfDeiJ0TynHBlwAAKTKS/fay3lKhOLi4jBs2DDcvXsXvr6+aNq0KbZv344ePXoAABYuXAi5XI4BAwZAq9UiLCwMy5YtE+9XKBTYvHkzxo8fj9DQUHh6emL48OF47733xDo1atTAli1bMGXKFCxatAhVq1bF999/j7CwMLHOoEGDcO/ePcydOxcxMTFo3rw5tm3bJhlAnVssRERErkwpU8LXq5yjw3C4Aq8jVJpxHSEiIipNmqxsIh4/ZayBMT3mo+/OF3K9ryStIQQU0zpCREREVHIpZCqolNanz7sSJkJEREQuSClXQWFHIhSc5l4M0TgOEyEiIiIXpJSroJDnPlS4iW9wMUTjOEyEiIiIXJBSroJcnvsqQTKZ5easpQkTISIiIhf0SHsPvp65zxqTy0p3qlC63x0RERFZlWRIhFqtwZoOK/Bz269zqFm6J5fneYsNIiIiKnnik+5Lzr2V5mnljWq1MhcctH6f3qgryrAcji1CRERELuDn7R9JzgeGTJacf1FvjsU9DbVKvNTDsrw0YSJERETkAr5NjpCc+3iUlZz3aDvI4p61Y48joHxgkcblaEyEiIiIXJC1xRTd03ecB4CQNK/iDMdhmAgRERG5IGuJkJ8xczr9BwPWFWc4DsNEiIiIyAVZW1W6vdq8F1kDraLUd4ll4KwxIiIiF6RSqizKZr8QjoZ7vkPn4P4OiMgxmAgRERG5ILXKzbJMrcFz3Sc6IBrHYdcYERGRC1IpNY4OwSkwESIiInJBajt2nncFTISIiIhckNLKGCFXxESIiIiIXBYTISIiInJZTISIiIjIZTERIiIiIpfFdYSIiIhKOZPRKB5/XvdNNK7dzoHROBe2CBEREZVyOoNWPG5QvRUqV6jmwGicCxMhIiKiUk5v0InHKisrSrsyJkJERESlnE6fJh5rmAhJMBEiIiIq5bT6zK4xLqQoxUSIiIiolNNnSYQ0KncHRuJ8mAgRERGVclnHCCkVnDCeFRMhIiKiUi7mYbR4LFcoHBiJ82EiREREVMqtPbLA0SE4LSZCREREpZxW0OVeyUUxESIiIirl3GQaR4fgtJgIERERlXItK3dxdAhOi4kQERFRKXcmZj8AoJJecHAkzoeJEBERUSm3XXkLAHBXJXNwJM6HiRAREVEpdvRspKNDcGpMhIiIiEqxkUcnOToEp8ZEiIiIiFwWEyEiIiJyWUyEiIiIyGUxESIiIiKXxUSIiIiIXBYTISIiInJZTISIiIjIZTERIiIichFf1Jvj6BCcDhMhIiIiF9Gj7SBHh+B0mAgRERGRy2IiRERERC6LiRARERG5LCZCREREpZTBoBePN3Zd48BInBcTISIiolJKq0sTj9UaTwdG4ryYCBEREZVSF68fE481KrUDI3FeTISIiIhKqeFHJorHapWbAyNxXkyEiIiIXICGiZBVTISIiIhcgFqpcXQITomJEBERkQuQKxSODsEpMREiIiIil8VEiIiIiFwWEyEiIqJSysNkAgB8Umu6gyNxXkyEiIiISikh/b8BZas5NA5nxkSIiIiolDJCBgBQqjhjzBYmQkRERKWU0ZwHQcOp8zYxESIiIiqFTEYjjDJzJqRScnsNW/KUCM2fPx+tW7eGt7c3KlasiH79+uHixYuSOmlpaZgwYQLKlSsHLy8vDBgwALGxsZI60dHR6NOnDzw8PFCxYkVMnz4dBoNBUicyMhItW7aERqNB7dq1ER4ebhHP0qVLUb16dbi5uSEkJASHDx/OcyxERESlkc6gFY9VKncHRuLc8pQI7d69GxMmTMDBgwcREREBvV6Pnj17Ijk5WawzZcoUbNq0CevXr8fu3btx584d9O/fX7xuNBrRp08f6HQ67N+/HytXrkR4eDjmzp0r1rl27Rr69OmDLl264MSJE5g8eTJGjx6N7du3i3XWrl2LqVOnYt68eTh27BiaNWuGsLAwxMXF2R0LERFRaaXVZ9l5nmOEbBMKIC4uTgAg7N69WxAEQYiPjxdUKpWwfv16sc758+cFAMKBAwcEQRCErVu3CnK5XIiJiRHrfP3114KPj4+g1WoFQRCEGTNmCI0aNZK81qBBg4SwsDDxvE2bNsKECRPEc6PRKFSuXFmYP3++3bHkJiEhQQAgJCQk2FWfiIjIWcQ9vC00Dm8sNA5vLDxKvOfocIpVXr6/CzRGKCEhAQBQtmxZAEBUVBT0ej26d+8u1qlfvz6CgoJw4MABAMCBAwfQpEkT+Pv7i3XCwsKQmJiIs2fPinWyPiOjTsYzdDodoqKiJHXkcjm6d+8u1rEnluy0Wi0SExMlP0RERCWRVq8Tj9XsGrMp34mQyWTC5MmT0b59ezRu3BgAEBMTA7VaDT8/P0ldf39/xMTEiHWyJkEZ1zOu5VQnMTERqampuH//PoxGo9U6WZ+RWyzZzZ8/H76+vuJPYGCgnZ8GERGRc7l0/ah4rOZgaZvynQhNmDABZ86cwZo1awozHoeaPXs2EhISxJ+bN286OiQiIqJ8WX7iA/FYqVQ5MBLnlq9EaOLEidi8eTN27dqFqlWriuUBAQHQ6XSIj4+X1I+NjUVAQIBYJ/vMrYzz3Or4+PjA3d0d5cuXh0KhsFon6zNyiyU7jUYDHx8fyQ8REVFJVB6+AIAKBpODI3FueUqEBEHAxIkTsWHDBuzcuRM1atSQXA8ODoZKpcKOHTvEsosXLyI6OhqhoaEAgNDQUJw+fVoyuysiIgI+Pj5o2LChWCfrMzLqZDxDrVYjODhYUsdkMmHHjh1iHXtiISIiKq08FZ4AgGZCFQdH4tyUeak8YcIErF69Ghs3boS3t7c41sbX1xfu7u7w9fXFqFGjMHXqVJQtWxY+Pj6YNGkSQkND0bZtWwBAz5490bBhQ7z00kv49NNPERMTgzlz5mDChAnQaMzT+8aNG4clS5ZgxowZePnll7Fz506sW7cOW7ZsEWOZOnUqhg8fjlatWqFNmzb48ssvkZycjJEjR4ox5RYLERGVLqeP7ULFgBrwr1zd0aE4nF7QAwBUMnaL5Sgv09Fg3r/N4mfFihVindTUVOHVV18VypQpI3h4eAjPPvuscPfuXclzrl+/LvTu3Vtwd3cXypcvL0ybNk3Q6/WSOrt27RKaN28uqNVqoWbNmpLXyLB48WIhKChIUKvVQps2bYSDBw9KrtsTS044fZ6IqOQ4cWqX0Di8sfDi8jqODqVYTf0uTJizYqAgCIJgNBjE8gnfdhIahzcW3vyxn6NCc5i8fH/LBEEQbKdJri0xMRG+vr5ISEjgeCEiIif3+doJCE/bAwA4Pfy03fcdOroFGw7ORVizaejyxJCiCq9InLq0H0MPvAIA6KQrh93qB5jo+zRe6fcRxn3bAfs0CRiARnhneOmZ2GSPvHx/c68xIiIqFVTy/E0R/yJqOrZ46/DhpfcLOaKiF/fotni8W/0AALAkYRMAQA8jAECl4KrSOWEiREREpYJSkb+xMOfcFACAWKUSqcmPCzOkIrf19Pc2rxkE8x6eTIRyxkSIiIhKBWWWL3zBlL8p4zNWdiiscIpc7IPbiFDdsXndAPNnoFa4FVdIJRITISIiKhWyrp6cqk2x+z5FlqGykZ5GGA3GQo2rqPy645Mcr+tl5vehUXJ7jZwwESIiolIha4tQcqr9e0UaZTLJ+Y4DvxZaTEVp3eMdOV7PaBHSqDyKI5wSi4kQERGVClm7gFJSk/L9nPsp1vejdDZJCutf4ZX05hYuvcz8Xw03XM0REyEiInIKaanJ+GvzIjx6kL9ERCbL/EpL1tqfCMmzrSLj7VEuX69fXC7dOIV7j2yPDbqrkiE5JQmJ8owWIc/iCq1EYiJERERO4aufh2LGg+/x/pon83W/KX2WFACkpiXbrLd796/YsGG+eN5EK51VJZicd4zQjTuXMCByKLr+LyzHeut2fomHSvNXvM6QVhyhlVhMhIiIyCn8qfwPABDhpberflpqMh7dz9x8WxAyZ4pt+meKzfsmXv8IcxNX4+jJfwAAJkgTnzSd7STK0fad3mRXvVRdZotYTPy1ogqnVGAiRERETkGXbdBybmb+2BJj/uiIR4/Mm3gbjJkJ1O++uSdT5+9EAQBOu5WcREgus/zaXtFqsUWZzpAqHg/pNrNIYyrpmAgREZHDJSY8hFZufyKUnJKInV5qXNSosTtqPQDgzr1zkjppaZZT6K/dyKwjA3D5ygmLOjqD/VPvi5tCLl00soLBhFaNOmOUe2eUMWa2iKWlvwe5IKBimcrFGmNJw0SIiIgcbs4vHSXnf0V8k2P9v3Z9l3l86WucPbUHscmXJXUSkh9a3Hfq2l7x2MPNB5//PcaiTpo+1aLMWWQdBwUA99LHAU1+fjG6KpqI5ReTzgAA3AQBcoWi+AIsgZgIERGRw+3ykrYGLb2xEGmptruofr29Qjze7ynDC8cn4G8P6dpBj1PiLW/M0rV0/94VpMkyE4uKBnMMOqPzDi7O3iKUVft6z4rHR93MLUIm5K270RUxESIiclL3Y2/j1+9H436c7anSpdUNlQrv/9jD5vUkuWDzWobHKQkWZSZTZuLzQ/JfOOpuPq+pUyDIaF5vJ+v4GmcTULaa5Ly6LvO4R9tBFvXT8tDd6KqYCBEROaku23rhI9UhzP6jo8W1fYf/xLBv6uDHleMcEFnx+J+X7bWAdHZ8v1tbXdpgzEyEPEyZX4GPFHooYe5C0hu1eYiyeGWdGQcA1VDeQZGUHkyEiIic3EF3y5WBJ599C8fd3LAQ+xwQUeHKbTyQNTVRQTx2t7HB6v7dryL5sbRVyGjKnE1WR5e5N5lCAFRQAgBup17NczzFxZRt8ceZT33roEhKDyZCREQlwM2blyTnaXLrv77/3bce3/80Hga9zup1Z/TL1eV5vqexV2PxONXGZ7HSzwttf5fuJp91sPEBj8zPqI17MyQI5jFJiXgEbZpzdo/tOPOLeKwxCQisVMeB0ZQOTISIiEqAN7c8bfPar7/NFY/nXJyHRcJeTP22ZXGEVShSZHlfyTnhwbncK1lhNFp/rfee+xFV1FUAAKfdVHj/+875en5R24AL4vGr5Z+3uN5IqyzOcEoFJkJERCXACXe15NzPmNlF8lHyBvH4YfpU6eyzsJxZFWXe17n5w/Oe1XK1KedB1EbB+kKLGpUbVMicZr7ROwVbN3+V57iK08tPz7Uoq6uRthB11nEMUW6YCBEROaHU1Mc5Xq9isD2NuqSpIvMDANTUqbCmS7jk2qHjfwGQtuQcOLrZ5rOm1BiL+vrMMVVeRun4oQvROyzueUJeCwAgl0nX25n54DuLuo5kstGalZVKLk2YFwzbUlThlBpMhIiInNC5a1E5XheQ+/TxhIf3CyucIrVafhYAYEAqGgUF46MamfuEjT41A98v64+Xv2uA95abNxode3a21ed0NlbGi51fQ/dKmZu2PlbI8cWKF8XzLR4PLO6b1P5tAM69ojQA6Ay5z2bLngi5aTyKKpxSg4kQEZETEgTLf/3fvnNFPNZB2tLx0aIW+PmX1yVl/TZ0RPja6UUTYCF5FB8nHkerzeNbsk8RX+T5H465a7De/Q4+XtTa5rPcYW4lGxX2FpqayonlK+Qnc4zBYDAPmk40WbbCZf3MHWn/yb+wZV94rvVUCk3RB1PKMBEiInJCeqPlrK9v/3wZqamPcf7iEVzWSFuEfvUz4FPjTknZfaUCn6dtkz5Xr4NgY7q5I5y/kdny1Qu1AQDaHLa4WOVne9VnWfoqykqlCgv7rbY7Bm+vMgCAauWaWlz7fvMku59TVNZFfIVXTszAOze/zrVu1kQoTF+1KMMqNZgIERE5IaPBclDvH54PsXj1KEz+d1ienvXO190BAAkJDzD6h+aYvfyJQomxMGRd/XlgyGsAAL0hf1tcNArqJB5n32jUoNfDZDRBLlh2KVavXB8AMLXv56hj9JJc+01zM1+xFKb379g/VilrIiSTlZwB847EeXZERE7IYLI+u+mo4RzuuOXtV/fvHrF422DAb7sW4pi7AkAiPi6EGAvD+et7xOOQ+l0AAKEt+gLbfsrzs17oNNHmtRar05cTSE8OZgeMgFeFyqjj30iso1Zq8M4TX2Do/rGSe9PSUuDmljnWZuP2xdhx+Qf0qjkKggA82WsCZDbWMioqQTaWiVIp3cRjk5XuVbLEFiEiIiekt9IiBADn3awW50pn0OLyvaPi+Tc/j8/fgwpZdPqO8d0MmS04Nfzr2nVvGelG7FCr7P9w5DI5nmk5GA2qSLvD6le3XH9p/Zb5kvM5Md9il5cRM+O+xax732L5D0Ptft3Csv6lg1bLNcrMGXN/q1xvj7r8YCJEROSEjEbriVB+afWp0Coyf+UvMe0t1Ofnl9ZkngnlqZB2Sfkacx/HNLL6cPG4sd7L4np3VSOLsgxyufVWNbVKgyE+XdBC8BfLPn38p3hsbXzVMvUZ/Lbpk1zjzY+Exw+tlnu4eVotz0sySGZMhIiInFDGYGlPo+1p8k8IQXY/L02bBqUT/co3Ggw4tPcPaE3m8UBuCuk079w2VR3g1wUju70hnk/r+KlFnc8Hr0ZZk/X1llQq27OrZj/7FX4YutXqtaWrX7Va/u7DX6yWF9TH60bkqb6bitPl84pjhIiInIxgMuHWxX8ANeBjApIV1uvVcq+Of9Oi7Xrmhm0fAbrHQHrPSTu9Y1ccnr+sLdb6asV43FXSFg4BtjMhfz3wTl/zqs8/df4Btx9eR6u6lgPA5TI5/hiwDZ03dLO41rR2+xzjUyqtJ1DfGvaK44yKw2bFtTzV16ittxSRbc7zzwMiIgIAfL/6NSxTnwYA3FXl8KUr2D8NfpnxX/zlnrmYYEVluRxqF62IyJXmJCgLd7Wv5DxNLn3f34cuFmd8NVNnjiFqUa0NnmphuedWhnI+FVFZb9mqVquK7W4zwHLGVcaqzoITzMQaqmpj85qbOrNFKFTrUxzhlHhMhIiInEBC4gN88cMgHD+1E9/oI+26x1SA72RHziiaeuMzizJfD9uJmYdJhuCa7fFBw9no694GHw1elafXy/4xVTaordbL7qWyvcXj1evfzNNrFobdURsl5wpBQDutLyYPWGzzHo4RyjsmQkRETuDtnztihfIcXj72GrRy+zKcF7rOsDmNOjfONrXa003aIvRBPfP4nzomH+wdFgWlUoWn2wzFB8//AE0ev+xvZ2tVW/HMH3bdN7F75qamn2itjxnK6sb1s3mKKzcfHX9Lcn5ixBl8M3ZvjttmqLPMGrNnGxZiIkRE5BR2eZl/HRtkMlTTSwcFvVQmzKL+n71+Q2CFGmjs3gAA4GOUftn392yHPc/tQTf3ZlZfL01rueeWI3llS4T6th2OU8NO4Y+R+6BSFO4Gs35e9nULumebmbVrb86rVT+1+4V8x2TNnSwJXBddBbvuUavZIpRXTISIiJzMDZW0tWbGM59htP8ASVkt/3oAgHeeD8erlV/A6mf+FK/5Gk14d+A3KONRBgv6/2j1Nf7xSCzcoO1gMBgwYZn1NYK8PMpYlBXFysgTAgbBw91yqr012V//f+dXwN+Qc0taQlLRJJjvPr/Wrnpu6qwLKjrPVirOjIkQEZGDXbtxLtc6r/d6x2q5u9oD43u8hWrla4plyVm61lRK+8bDFIeVG+dgj6f1aevenpaJUGEZXb6veDwubE6+n/OPOgaxSsspfLVMmYOSl60dk+/nZ6XTSQeTl/G1r0WonG+AeCzLYeYdZWIiRETkYAv+GlmozzM4wcym7A5G/YXFSZttXve1s7sqP17v8wHG+Q/EBw1m5vne1/ytd3cNcjdPv++pbIg/R+4Ty1er/rMY5Jwfwb+2Eo/LGexv2Snnl5kIda3ev8BxuAKuI0RE5GAmuRpAit31rW0caq+x5fvh2/t/5vv+/Hr3+FQYVba/csr6VCzS15/Qa16+7hvT6y1ot6Thm2yfWY8GA/Ba3U/grTa3BnXSB2C3KgYA8F3UB+gU3Df7o+wWcVDaDdbLvW2e7v/nqW04e+UAurYZmO8YXAlbhIiIHEgwmbBPE5+ne1Q28iDv9OEr9fXukvKRfr1Q1aDCb91W4almQ8TytDT7k6+CupVDEgQAnu7exRRJ3tUp39iizNuzDHw0vuI4IkWW8TiV1VVsPstg0OPrDbNx5vIhm3UO/Pc/yXmaPjlP8fqXq8IkKA+YCBEROVB8PgbXljNaX2p6Scfl6CKvhQ+fXCEpn9p3Af4adQz1qjaFt5efWP7czy3x6Q+DAABbIpZjycqXre6lZa+ffp+DuV93zXOCta573tYFKm5BFWpblHlnG9ydgsy94dxl0nFQ125fwMTvOmPr3p8w6od2WJa4GYP3jbb5egE+1SXnDSu3y0fUZC92jREROZDOYP9CQO/Weh0/X/wOsztY3+CzZe32aJnL1hFZv8Cvq1W4jnPY9kMD3FOavw78t3+J53pPtTumrBY83gh4AIYVvfDR+D051g0yqPDdwE0QBBOq+AXm6/WKS1Aly5lu/uWqSs4Ht5qGg6fMA7F1JulA5w83j8Qht8fYfWUBYMfsdpUis5Kv0YTne7yWj6jJXkyEiIgcSKfX5nj91QqZXRz9O4xG/w62WxLsobGyzkxGEgQA1+IvFOj5ALDJ4xE+Sj9evmoilhp2S64vD/0SrWp1gEZhe+NTZ5K9225W0Cios23a2rVFX7Q/9hX2KeOgN0r/TG8rkmC5vrVtQpZuto39d+Q9YMoTdo0RETlAQsJ9hK99A3fuXrJZp5oOGP9k/gb55pePe/5mb6VpU62WZ0+Chnh1Rvu63UpMEmRN16YDrJb7yswrPusFaSvfPRub5tpiMBkAAPW0csksMCoaTISIiBzgkzWD8Hnadnx2ZIpYtq7Lz5I61ZRVs99W5FRy87pD/+wKx7/71tt93/ad39pVb3YO+2Q5s7razK/LSuWsd+Wp5ebWNr2gl5Tb2jLl/NUoq+VC+vYnXAeoeDARIiJygF3pU60vaMzdUgpBQIOg5njRr6dY5/3nfrZ6b1EymgyIuX8LU6I/x6uX38OD+7G53vPFdwMxJ+77YojOuanTW7n0MODSjRP49NexOHFxr83670dYX3zRZMpIhKg4cIwQEZEDZP9XqDJ9SvzMvp9D2PA6apRvgLJe5Ys9Lr1Jh+i7F8Xzzlu64xV5O0x86Rur9RetHIkV6otWr3347dNAlh6wCsaS+5VTWVUFl3AzxzpqhRtgAqLliXg94kXcUsmw49/9gMp6SnPaTW+13JjeIiRnKlQsSu7/lUREJVj2pYDkWUpmPbuoSF+7nFGBBwrre2bpDVo8TLwrKfvGtB8TbTzrexy1Wp6WloI1muvieaDgjd9ejMhPuE7hnQHh+GjTJDzTZJjNOmkG83o/WTdLvWMjCQKAJ7TWtxURTOwaK07sGiMicoAkhfTXb6q8+H4db3vpgM1rOkMqTlzclOszrt04i9eWtbR5/ZPV0oRhfrvP4KH2tFHb+ZXzqYjPh65Fp6Z9bNa5k5Zzi1F2USrra0iJLUICE6HiwBYhIiIX46Zyt3ntZ/1BwI5ZTu//NRRHPG3vxG5SSB9SpWJNGzVLj4wExl4pNpLfjF3jmQYVD7YIERG5uC9avI/2NrppbDnibvtLXykIMJikU8jLetu3e3pJ5q+uZPOarY1TP/xlBMZ92wF/7cscGM9ZY8WLiRARkRPwNOV/I9X8WNlhOfr7PIGlrRegR9N+kOWxNcMaWfpbMMhkOGqULswoV+RxMZ0SaPpA20sIlMmyLcpTpszWsTXGKOzTJGDG5U/FsluPrwAATBYjyagoMBEiInICrwQMyb1SIWpZqz3efXYZOjbsBQDY65aYY329XtrCU0lv+SV9asRpeKTvVXYnyyarDQ3Ou6FqYfLzLg9fo/WWn8saAeO9eyNE64UZ/a0vNXDt9gXcuHMJ/6jMg9VPudm//QrlH8cIERE5gcp+1Rz6+u4mAak2Fv4DgBt3L6J2UBPx3NxakVm/q6IeAMDXKENKtn9ir3zJdbaJUOfQiPNq/09tXwSw5K/JuG2KlSw5QEWPLUJERE6gcS6bpRa1+c0/sCgbU/Zp8Tjx8UPx2GQ04p4yMwl6wa0dFr34GwDAyyTtAutiCoKb2vbg7NJGZedMr4PP7bcoOyS/ibMag3jeWutRaHGRbUyEiIicQJUK1R36+t1a9MPp4afRPjVzinuvpi/APb2ryyRkNnUsCB8CkyzzC79pYGYS55WtOWPmU0uLKmSnZG8i5Olh2V3Y2FBWct6v/thCiYlyxkSIiKiYPU5OcHQINl1SJYnHKqVa7PwSkDmY+hflOfF4mF9PPN0uc80gT5m09aeiX+WiCdRJ3VBLz8d69kBtrQwzKgy1qPte0ATJubtc+tl1b/NCocdHlpgIEREVs5MX/3V0CDZlnTumVGrERMiYvtrx8bPS3eTfeOYzybm3wkdyrlJlywxcTEi9J7Fh7Cm89OQsi2vPdhmH08NPo69QFwDEQdIZPNxK7gKUJQkTISKiYrb52NeODsEmY9aeHUEQp8QL6Yv8Xbwl3VJDJpN2BXmr87YeUWnn5uaVax29yXJ2WF9T3aIIh6xgIkREVMzU9izd7CCNkdmV5etdNrNrLH2MUFxizttI+LlnLpyo4DI48NDkngjd1cdYlL03bF1RhENWMBEiIipGDx7F4A/VNUlZJYPzJEYfPbcawaiCN6qPgo+nn5gImdK7xu4nXMnxfj/PiuLxTx2tr5fjSrw8fHOt06u6dCxQPa3cJRagdBZcR4iIqBhFXdglOf+u3WI0rNrcMcFYUda7AsKHbxPPM1uEzF1jG1TXc7z/6Q5j8Mea31Be7oumNUOKKMqSw9M998Ukg/wbAJaNQlRMmAgRERUjo0kvHj+jbIq2dTo7Lhg7iC1CguWKyd3lluNY/LzKYsPoI0UclfN6FvWxAZnbi3i65Z4IlfGuKDmvp6pV6HGRbewaIyIqRldvmgcbexmB94f8nEttx8tIhPQ6raS8q7wuvkhfRJEyvTd8PcZ6dBfP7enialC9BdpovVBPK8cgeQvMev7HogyRsmGLEBFRMVquNXeNlTWaIJc5/79FHynMMU659AF21O6AKnoBt1UydKra3WLGGJk90XQAvj34j9315QoFfhh7oAgjopzk+W/hnj178PTTT6Ny5cqQyWT4888/JdcFQcDcuXNRqVIluLu7o3v37vjvv/8kdR4+fIihQ4fCx8cHfn5+GDVqFB4/fiypc+rUKTzxxBNwc3NDYGAgPv3Uco+W9evXo379+nBzc0OTJk2wdevWPMdCRFRcjIbM7ROi1c6fBGX3zm/PwpC+I7pa5TrbZuRV83od8GGNyfiu5eeODoXskOe/icnJyWjWrBmWLrW+bPqnn36Kr776CsuXL8ehQ4fg6emJsLAwpKWliXWGDh2Ks2fPIiIiAps3b8aePXswdmzmUuKJiYno2bMnqlWrhqioKCxYsADvvPMOvv32W7HO/v37MXjwYIwaNQrHjx9Hv3790K9fP5w5cyZPsRARFZfIo3+Ix583muvASPLnX49UxKrMXxsapZuDo3Fuz3QchbZNejo6DLKHUAAAhA0bNojnJpNJCAgIEBYsWCCWxcfHCxqNRvj1118FQRCEc+fOCQCEI0eOiHX++usvQSaTCbdv3xYEQRCWLVsmlClTRtBqtWKdmTNnCvXq1RPPn3/+eaFPnz6SeEJCQoRXXnnF7lhyk5CQIAAQEhIS7KpPRJSTf49vFhqHNxYahzcW4pMeODocu3T9vrEYc9afc9eOOTo0Ipvy8v1dqG2z165dQ0xMDLp3zxwo5uvri5CQEBw4YO7/PHDgAPz8/NCqVSuxTvfu3SGXy3Ho0CGxTseOHaFWZy7NHhYWhosXL+LRo0dinayvk1En43XsiSU7rVaLxMREyQ8RUV4kPLiEluGN0e2HBtCnSX+HaFSZrSi+XmWz3+qUqhqtb/PQoHqLYo6EqGgUaiIUE2NeCMHf319S7u/vL16LiYlBxYrSqYJKpRJly5aV1LH2jKyvYatO1uu5xZLd/Pnz4evrK/4EBgba8a6JiDK9+ucA6GUyxCmV+GPnDMk1g9E8dd7LaDkV3VmNbPOmo0MgKlIlb7ReEZo9ezYSEhLEn5s3c15Knogou1NZ5uLeSomTXDMazIlQSVozuHPzZ7C8xQJJWQ+hhoOiISp8hZoIBQQEAABiY2Ml5bGxseK1gIAAxMVJfzkYDAY8fPhQUsfaM7K+hq06Wa/nFkt2Go0GPj4+kh8iInsk3L+E3zeNhpcpc4OtIN/qkjorD80DAJSc9iCz4PqdJOctKoY6KBKiwleoiVCNGjUQEBCAHTt2iGWJiYk4dOgQQkPNf3FCQ0MRHx+PqKgosc7OnTthMpkQEhIi1tmzZw/0+swVWCMiIlCvXj2UKVNGrJP1dTLqZLyOPbEQERWWmf97Ae88PITH8sy1db66uQ0QBPz851Cs2/QyDnqYf6clKUpWY7ybWjpVPiHlnoMiISp8eV5Q8fHjx7h8+bJ4fu3aNZw4cQJly5ZFUFAQJk+ejA8++AB16tRBjRo18Pbbb6Ny5cro168fAKBBgwbo1asXxowZg+XLl0Ov12PixIl44YUXULmyedfjIUOG4N1338WoUaMwc+ZMnDlzBosWLcLChQvF13399dfRqVMnfP755+jTpw/WrFmDo0ePilPsZTJZrrEQFabY63ugUKpRvmpbR4dCDrBPobcoi1co8ONvA7AwpXStX+ZfrrajQyAqNHlOhI4ePYouXbqI51OnTgUADB8+HOHh4ZgxYwaSk5MxduxYxMfHo0OHDti2bRvc3DJnS6xatQoTJ05Et27dIJfLMWDAAHz11VfidV9fX/z999+YMGECgoODUb58ecydO1ey1lC7du2wevVqzJkzB2+++Sbq1KmDP//8E40bNxbr2BMLUWFITb6H7rsnAABODDkKhUrj4IioQEwm3Lr8FwIC20Pp7pdr9X/3zrd5rbQlQQAwsPN4R4dAVGhkgiAIuVdzTYmJifD19UVCQgLHC1GObt8+jF7/jAIAHBrwDzy8/HO5g5zZrsh5eO3GH+hlcseCkYdzrd8yvDH0edxu4vTw0/kNzyH+u3UGL/wzGIO8OmPGwMWODocoR3n5/i5ZHdVETkqhyFzzqse6LjnUpJLgtRvmFaC3yVPtqq90gX9O1qnaGFEjTjMJolKHiRBRIRBMmXtIJdqx2zQ5H33KA5h0KdClPJSUXzz9a673Vsk2If6btu8VamxEVHSYCBEVAoNR6+gQKBfxcWexJ/IdmAw6i2sx0QfQcn1nNPs1BKv/mSK5NvDYRzafadA+xmvfN8VleeaE+DVt3kG7es9arV/vsXn2VRUdf/USOQv+bSQqBIZsX67bI6ZDMBodFA1ZM27TC5hw43d88avlRpg9dmVOxDj06Lzdz9wU+RZ2qaT9Yo9TzS1KvibL/rIbD6agzr26eC14ud2vQURFi4kQUSF4eF/65fnGnW34Yxtn1jgLwWjE2fQ5sitND3DhzDqbdffCclzQneu7sWPnmzDppdf+iTlkUbdxfXNrUHevzNWX/3pyDY4MPgSZogKO3X8ZQf4N8/M2iKgIMBEiKgQjzn1tUfbOfeub+1Lx273/Y8n5mtPficer/3wx1/vDdk/E5Jub0Gx1G0n5HiRLzr9pOR2eHuUBAG/1W48qUGGgdx1UrdAIbmoPsV4eJ5gRURHK8zpCRCQlmErahgmljMkIyHMeoH7wrjQpPZRyWzyen3AyTy8nmEyQyeXQ61MsrrVrMkw8VqncsG34Mem96f+VgZkQkbNgixBRAUWd+N7mtZRH16FPvl+M0biWPfvmo+eKJjhy5GvoUx4i+cEVq/Ue6R5Lzm8pFThyeEmOz369Yger5ab0HeRTUzL/XJ/yqoUTLx7PNV6u2kbkfNgiRFRAsYm3bF4L+d/TCNIbsGW0/QNwyX4TLq8GlAq8fG4ZvM4sgVYmQ+Qzm+BTVro7eoLRsvXm5fPfoOOpbwGV5XOPv3QcCsix6OdmFtcMxlRcvbgBiw/OB1SAQhDwUf8NkOWhv4tdY0TOgy1CRAVkNFnuMZVVtEr67417t49g/96P2aVWyB7L5dDLZIi6+IfFtX1WBkADwB6V9SYapVwJmdz6r0eDIQ39oz7ELpX5z88ok+UhCWKTEJGzYSJEVEA6O9YQSkm8Ix73+XsEXrmyCrv2fliUYbmsMl4B4rE25QF+tWMwNAB0VleARhDwStmWYtnvXZZa1Pt5y5gCx8gWISLnwUSIqIByaxECgLOXNorHqektDa9fW4dxK1pCm/KgyGIrzRIeWh8PZDJlrt+0Ytt4fJRlMPScyt1tPm/x4J048NIxTHx6pVhWN6gjQiDdpHlp2nXJeQ9lObtjzhgjxMHSRM6DiRBRAaWlry3ztLICWsLdap2Xzy6DSZ8KwWiQlO+T67F1v+2dy8m2+VtGWC2/F29OkEzax9ibKE2WGgZ2xNgyzW0+U5Vlz7gMwWUb5xiHt8zKICMb2DFG5HyYCBEVUJoxDQCgVqjwQY+laASN1XqtVrXG+PBWVu53re059KkJ2LR9MuJu5b6re062mOKtlr9x/Q+s2TwaHVaHwC1by0vjev3wbMuJkrJyJhk+rDnQ5uu8HLYYbwY+afN6cJVQ+4NOx64xIufBRIiogLRG8/YabnI1Aiu3xprhR63W08tk2Ke03HbDYLTc+6o0+2PXTLwZswPddoySjJ3Ki9g7UTle//DBISTJ5Tgky0wyA01yyGQyeHlWlNSNHHkKzzwxz+azNGovDO76CZ7zqGH1euNqXe2OW+D8eSKnw0SIqIC06S06aivdKvZI1ifnXqkUOfbooni89eACi+uPE27it63j8OiedMmB6Cvbcf70KujTEtE9YoTk2scNR6OxjZa4DN/1/gkA4OnpL5a9UamL3XEPCX5Ncj6jcjeMKdMCNat3tvsZGdggROQ8uI4QUQEY9Wn4NfkKIJPBTZ6/RGhp/ElU3jIez/Sx3KajpDt04AssPPMdfnz+b3j4BgIAanhVBeLNixGWyZKUZJj++zPYqzBg26ZD+P7lzEUK++x9AwAw4txqSf3hPg3Rp/XrOHktAmdSb1iNo6pJhioB5jWBVGoPzA16GlpjGl7s/oXd70WlzBw03Uvtj5d6fGn3vRnElaWZCRE5DbYIERXAoePfQZ/+reap8RHLv6w/EgFCzts+ZPXW/b3QpSUUenz58c+uOTh+7NsCPyf2ThRGX1qBs2olnvotTCz/9lFmcjP58ipxpeYMexXmAeWHFJkDy/VpieJxeFq0pP6YLp8CAAaFTLcZy9vNX5ecP9flozwlQQBQtXII6gsqtJB54NNBf+fp3gzsGSNyPkyEiArgVvxV8biyb3XxuFvIVESMOGHzvkpW1lL872pEIUaWP1ev/I0p0Rsx7PTiAj/rg4hXxeN7SgU++KUzkpPuioljhs4rmyHlcQwEowF/bZ8iuXYvxjz1/a+979l8HR8fc0tTrWqdrF4vK8jQrsWofL2HrBRKFdYOP4qVLx20udii/dgkROQsmAgRFYA+y/ie0OaWX7ZvVelp9b7Hggm1TdIWo4dJtrfqKIiHd45BMFoO0rbm1v3McTn6lId2v8bv2yZi+I/NEH//krlAEBAJ6bYWa40PcO/+RYt7HykU2PTv+9i4cwZmxPwjuXby4p+4H70PFx/9Z/V1p5VvazMp+bDOEAzxbYSdLx2zej0/5DJ5rqtIp+gMaPvRDvRbug96ozTj5WBpIufDRIioAD6+b97V3MtkspiNBAAvdP/c6n1JCjk+77YYNZE5rijmkfUFAvNNEDD6+yboFDEcP28dbdct6izjYHr+an3TUUPqI+hTHknK3ondjWMKE57YMgAGXTLe+6Wz1Xuf3jPJarkeAo7dP21RPuX6b+iyaxx+Srlq5S6gV+vJkvMQmRcAYIB7NTzTbjZm91sDhaJ4h0KGfbkHMYlpOHEzHhuO3bZah2OEiJwHEyGiQlBd5pZ7pWxqBj2BjcOj0E1uHlv0XmwkjPrCW1PowoUNOJS+1t/P9w7DkBqPr9Y+hZE/NkOaldWsU5LuYsyZzB3Z7ysV+PvvqQAAk0GHE1Hf4uSx79FiXUe0XN8Rgl4LCAJ+2zpe8pwWv7bFelPOrUlNBOkihJ/E/YsNupg8vb/Pag5CQMVGkrKF/TdiQb0RmPnMqjw9qzDEJKThi4hLuPkwc1+z2/HmY4PRBJNJyBwsXezREZEtTISICqBBevfWK/VfRGKaHslag826r5UPEY9H+jQUj/2UnuJxbNxJFJarWZ4Vo5Cjxbon8F3aDRxVmPDPIcuBwiF/WHbjTbsbgX92voU5qzrhpTOL8eLpReK18ava49iJFXj33t4c4+itqWRRlmIy4PjQnNcCyo3eyvpL3l4V0avtNLi7+Rbo2fkx+qcj+GqHtAtv0Y7/8F9sEtp/shN9Fu+FycSuMSJnw0SIKJ90qfE4LzePvfFwK4em7/yNJu9st/iy+7L+y3jBszZGhi3Fjy1nYbBXbYzrtVy87qbIXP/m32PfFFp8F2NP2LyWkHJPcn718jabdafc/B824bFF+T6ZFvuubM4xhikBHfHpC5YzrOq4lYdSaXu5gU/q5L5Raou6fXOtk1+pOiN+3HsN0Q9Scq8MYOeFWJy5nWj1Wo+FexCbqMX5u4lI1pn/f7F/t3oiKmpMhIhycefmAUxbGYrfNo9BSpJ5JeT/LvyJt9b1EusYBW8AgEkAPtl2QXJ/t5ApeGvgBiiVGrRuMhRvDtgAD/cy4vU+zTLH73zw8DC0j/PWRWTLj6nWx9UAmWObAPNaSH33Saee1zLZN/X/22Trg5gBYGa1Z/BymHn39veqPSOWKwQB7/RdAwB4O7CPxX2r2ryDJ9vNxHC/JgCADirrm5pWqRxsV4z58cb6k3hv8zl0XLDLrvqTVh/PvVK6AB83VPLNe1cqERUNmcBpDDYlJibC19cXCQkJ8PHxyf0GKpVeCW+F/elbNSgEAX+0+xh9D8yW1FnVYQWe+S5WPL/+seUXfE6arGwiOQ8zueHjoZFQqj1t3GGbUZeK6Gs78MzB2TnWWx88Bwcvb8KWBydwQSltodj1zEZ0+V/eWlzKmQB3mQINNOUwqdPHqFG5teR6QvI9eGh8AZkMKkXmGKGu4U1xT2b+NTS9Sg8Ms7K+z7ELf+Dzw5/glGBuoRmgqYx3Xtiep/gAQGswQqO0TPIEQcDCiEtoFuiH5oF+CP4gc/batB51MalbHZvPvBz3GN2/2G3X6x+c3Q1lPFVWYyCiwpOX72+uLE2Ui8uCVhzdapTJLJKgPppK8PZtACAzEVp35Caea1XV7i6Qz+q8iDf++0U83y5PQ90tozH22V/zHO/iDc/jh7TrudZ7LuoD80G2JGjvgAj4egVgb//t6PBHmOTa0savIlmXhBmXfpaUz6r2DHq3eAVlfYNsvp6vZwWr5X8NPYjUtHh4upeHykZ3Wcv6/TEbMgw+NBcA0LPeczm+N2sWRlzCoh3/4f1+jfFS22qSa88s2YfTt80LWj4XXFVy7fOISzYToRM349Fv6T5J2S+jQtChTnlUn7XFon4AW4KInA67xohyEeZVM8frk7t8jq8jL0vKZvx+CnP+PGP/a7SbaVG2ONH++zOs3jLWIgmqIdj/7513gp6Gr1cAAMDXu7Lk2tOayugYPB69Q2dgTJnmkmtDO3+YYxKUE43KA37elW0mQRka1euHUX5N8XpAR7RrYd9yABkS0/RYlD6Q+e0/z2D/lfvitZsPU8QkCADWR1mu5/TmhtOoPmsLftx7TVKePQkCgAaVzN2kQ0IyP48yHirM6l0/TzETUfFgIkSUA8FoxNWk6Bzr+FdsjHVHLb88Vx3K+b6iMD/L2J8MH7Z5Uzze2Hlpjvf3e+Jdm9fe7rdOPH7tmZ+x66nf0QLu+LB6/3xEmncymQyT+67C6LDM92AwmnD6VgKMuczGWrnvuuR8yHeHxMUNn/g093FAq9P/LN/bfE4ss/aav40LRTkv8+D3d55uhDY1ymJ6WD0cn9sT4zrVyvV1iKj4sWuMKAcfr3sS+xS2p8QDwL7LlmvyZJi38Qwq+7njFTu+BKua5Lgll65E/O6qrhj9xAeoEtTOvoCtKF+mFhY1GI1kbSJqBD1hs95X9V+GQild32eUb2P8kGBumco+Jb18ubr4afjhfMdVGCasPobtZ2PxSqeaMBgFpOiM+LBfY8jl0u6+/Vcs/4zG/3IMbWuWtfnsaT3q4vOISxblBqMJCal6bDguXSxx++SOqBfgLZ6rlXKseyU0r2+JiIoZW4SIbEhJuInVujvieRkTUMVkOeYnNjHN5jNWHriB+X9JZ5EduPIA87eeh84gTXqWdrXc3+s3wz302vUK7kRbdsFkJ5isbGAGoIxfTXRt8zqefuJtyGQy/NTmHdSEGopsDRqdW79uce+rT36PxlBjoHs1i2vOYPtZ87isb3ZfxQ97r+HXw9E4fF26mKPeaMKBq5aJ0LazMXhn0zmLcgA4826YzXFBKXojgj/4Bx9sydyO5PrHfSRJEBGVHGwRIrIi+tou9NnzmqRsQ98/Ua5sLcQ++A/dN2d2B6UZct/H69SteDSt6gcAGPzdQQDAnyduo2/zKpjZqz4UchlqVuto8/5B/4zFvy+fzfE1Fv5mfZaXm7uf5LxFgwHY2GCAeH7v0RWU9almdc8utdoTvw4v2MKHRSVFZ72lTpmlNehY9CP0X7ZfPPfzUCE+RW/tNtQP8MaDZB1Gd6gBL435V+PqMSEY8t0hSb2m7+Rv53kick5MhIismL9HOjPs+NCjUCrNYz/8y9WBWhCgS58RlrGatFopR0VvDW49SkV2zyzZh0UvNEdZz8wBwbGJWny75ypaBvmhV2Pz6sunhp2CVpeM1mukXSrxCjkgCFY3qboTvRfu7uWwIvW6xbXfn1iY63utUKb4x64kpenhpVEWaGHBD7O0yGS17UwM/H3cEHEuFptO3ZFc+3poMN7ddBYXYpIs75tsmYi2q1UeE7vUxpJdly2uZXi+VVWb14jI+TERIsomJekO9iJZUpaRBGVY3GQS3ji1GHPrDMG5VHOL0POtqmJCl9oY89NRq6sMv77mhNXXuxOf2bUmk8ngpvGyWm/B2j5IMCTj/SG7xNab+3FnEbZrvEXdqMGHoFZ72H6TDpS1lebiB73ytabOw2SdzcHo3++9hu+zze7K0LZmWYSPbIO283eIZa2rl8GkrrbXCXq1Sy24qeT47G/L8UIA0KGO9WUBiKhk4BghonR67WN8//tzCMm2ds7KNnMt6rYLfgV7R5xCrw5v4tgN807snholKvm6Y/Mk2wOSrflgyznceiTdymFiuVYW9X7S3sRG40NcuRoBk0EHwaDHwXNrLOqpBMFpkqAHj7XYevousq7b+sexzBl2f5+Ntbgn6sYjNH1nO/Zdvi8p//zvixgVfgR3E1LR8v2IPMfyy6gQyGQySavcU00rYf24duhY13Yy46FWYmLXOvh9vLSVLrhaGbQM8sOTjQPyHAsROQ+2CBEBuHnlHzy5d4pF+cK6w9CygfXF++QyOY5FP8Le9C9sH7fMGVetqpXB0fQEKTcmAejwyS5c+qA31Erzv01eeWoFlmRbbVokk2H4T22QCiOesLLG0af1Rtj1urZ8HXkFVcu44+lmlXOvnIPb8alo//FO8Tzj/f1yMLMlZ9Kvx9G9gT/c1ZmtQgO+NrcWDf3+kLhCd7LWgMU7zd1TO+ZnPhMAvni+Gfq3rIo/j9/G5LUnrMbyRs+66FCnPABzF+aKEa2hNZjQKw9JTK0KmS11bz5ZH2M7cjo8UWnAFiFyeYeOLrOaBLVT+qF76HQrd2Q6fzezC6xxlczp5StGtsaq0SHWbrHp5K14yflr5dqgv5vl+JOzV7fhhMKIiwrgeyv7iXUNkb6X+4+1sHcnndO3EvDJtguY9Otx6I3WZ6FZE3XjEb74+6I4E04QBLzy81FJnbpz/sKDx1qLexvM3Ybr95Nx7k6ixWrMZ24nIC4pDb8fs1ynKUO/5lUAIMfEbfQT0oSxS/2KeUqCAMDPQ43VY0Lw27hQJkFEpQj3GssB9xor/Q4dXYbRZ7+2KJ9Qrg3G9Fpusa5Odi3fj8DDZB0A4OpHT1qsX5N91lJWnz3XDG+sPymePxdcFQuea2ZRL/s+ZLk5Pfw0APO08Tpv/QUgswXjTnwq7iakIria9fVzPv/7otjyAgDX5j8pGdAsCAIW77yMZoF+6JTenaQ1GFFvTubu9ctfbIlxvxzLU8xv9KyLvZfv4+DVh7lXzmLdK6FoUyPzvbT/eCdux5sHq/8+vh3O3UnAi22rcbd3IhfDvcaI7GQtCQKA0b2W5ZoEAebZTwDwRJ3yFkkQALQMKmNRlmFgcFV0q18Rb6w/iR0X4rA+6hbefrqhpIstr76qP0o8PpBlEcGPtl7A32djxe66v6d0RF1/6bo3zy7bh+PR8ZKyGrO34udRbRCXqMW0LEkbAEzpXhcvtg2SbFAKwK4kyFOtQLIuc9kBWwORc/Ji2yBJEgQAa8a2xfqjNzGsXXWU99IguJrtz5+ICGDXGJVkJhMuXfwfft70Mox624sa2rL/4JcWZU8ofDG1QnvJLDG90YTIi3GIT9FJyi7HPYbeaG5QzWnW0bDQaijvpcaRt7rDx838b4/INzoDAMp4qlEnS0LS6v1/LO6vakcP1Ujfxjg+9Ci6hEwWy1bsk86cyjpmaXnkFcm1jSduWyRBGV764bBFEgQAC/+5ZJEEWbPhVctVsZ+oU0Ec/2NN06q+Nq9lGNm+hkVZYFkPTO1ZD+W9NFbuICKyxK6xHLBrzHntP7QIr1z4Xjwf41kHrw38A7ei90IQTAgMesLqmjsZrl2JwDN7p0rKTr50AnK55VTu7/ZcxYdbM9esWTqkJT7edh43H2auF/TP1E6oXdH6tHcAMJkEscVIEARJV82d+FS0+1g6ALhr/YpYMqQFPNRKHD4ZjlEnPrf63EPP/wvIFfDQZCZTyVoD9ly6h/Grcm6Z+W5YK/wXl4TdF+/h0DVpl9QrHWvimz2W44/yoku9CvhxRGvIZDLsvnQPw3/M3I7jzLth8NIosf1sDF75Wbpg485pnVCzghfe+d9ZhO+/jnr+3rgYa7nuT06JFBG5trx8fzMRygETIeeVfdxMOZOAiBcPo8MvrZGSvsbOYHUlvDnYchXgvQc+w/hLKyVlR57/12IF5gxhC/dY/SLOUN5LgyNvdSvQOJRvdl+x2IrjqaaVsGRISwDAhl1vYW70/yzuyxgPlOFyXBK6f7En33EAwNiONfHmkw0Qvu+a1S0oGlTykQwSz7D8xZao4K2BRqlAw0o+VrsKrdl+NgaHrj6Er7sKw0KroYyn5S70BqMJh689xJDvzas8f/NSMMIacdo6EVnHRKiQMBFyXj1/bIK7dqzDd2zwQazb/hqiHp7DJ4P+xu3bB/F0tpagIJMcW0Zadv0A5jFATXLZUuHce2HwUBdsuJ0gCKgxe6tF+dl3w+CZvt1DSuojhKzLXP14YrlWeOWpFZL62WddAcALrQOx5shNu+LI3rKV9XkrRrRGl/oVAQDrj97E9N9OAQCqlfPA7uld7Hp+Qf249xpUSjleauuce58RkXPgYGkqNQz6NExa9QTKKj3x4YuRYnk5mRJ3kfOu8ACwc//H+PihuUsmYq3lWJWhnrXwUru3rd4bn6JDx0935foaBU2CAPOK0i2C/CzG6TSatx1Te9TFkJAglPeSDvwd3u0Lu549pUddVPFzR2KaHm8+2cBqwgUA374UbNG992LbIHHdn4wkCACeaxWIgcFVcSw6HnX8bXcJFraXO1iOCyIiKggmQuS0khKisePwl9grSwOMaTj5QyMs67IYScmxOCM3J0FrQt7DC4csV37O8MaNP21e66ksj1kDrV+/FJuEngulXUyzetfHw2Qdtpy6K07RLkzhI9qg2XuWrU9fRFzCnkv38Nv4zETOXRDg5i5NjN7acDr7rQCACl4ayU7q+2Z1xa+HoqE3mbD9TAzikrToUr8ielrpanq/b2ME+LihenlPi2symYyzsoioxGPXWA7YNeZAgoCBK5riYi7dX3ue2YiO/5Puul7eBNzPZT7kxq5fI7BSK6iUbhbXbj5MwRPZWoK2vNYBjSpnzmR6OfwIdl6IQ83yntiZPgOsMJy7k4h7j7WSgcUZ3uvbCAsuPQ0A+LHZNLRuPgJpeiOG/3gYqXojTt1KsLjn51Ft8AT3wiIiF8OuMSrx/oiYkmsSBABlytTElPKhWHj/AABgdqXuGNJzIdLSEtF6bXuxXndlOfxjyFxXp2ZgB8lzTCYBz31zAFFWtsVoV6ucJAkCgE8GNMVPB65jUOvAvLytXDWsbP4L2695Zfx5Qrpz+tyNZ1HbvR+Gh+gQK++JP4/fhkwGixlfAGdUERHZi4kQOR2T0YB5d3fkWk+d3pg5LGwxWlz6Ew1rPQlN+jRyNzcfDPOsjZ+SL2NWQGcMDVsMre4xzl/bgbpBHSXPOR79CM/aWP35t3GhaFXdchXmCt4aTOtZL69vzW4LnmtmkQgBwOXUttB6NsDE1cdt3vvrmLZFFhcRUWnDrrEcsGvMMXbtm4/XLq8Wz+sIKvwn01vUi3z6T5Qra3vPJ4NBi4SkOyhXxvYA29Erj+Kf85Y7oMtkwOE3u6OCt+MW5ot+kILEND2eWrw3T/exNYiIXB27xqhEy5oEnXzxONLS4vHiuu64DwOqydywoPeP8K/YBCv2Xcfvx/5FJV83LBzUHN7ZtqZQKjU2kyBBELBox39WkyBfdxVOzO3h8P2pgsp5mP9b1gPRD1NyrV/GQ4Vf8rjRKxGRq2MiRE7FZMycEt9S0ECuUMLDszz+GHlCUu/9zefww17zFhJn7yRiVPhRrH2lLcb/cgzbzsagrr8XRj9RE8+3shzDE3XjEQZ8bdkVdnB2N8jlgEahcHgSlNX7/RpbHTwNANN61EVQOQ881bQyFHYuYEhERJnYNZYDdo0VL8FowNGT4Xj59CIAwOHndsPdoyyORz+Cm0qBBpUy/wysLRxozaUPeuP5bw7gxM14fDesFU7ejMeSXZct6mXfZd3ZWJvJ5u+jwaE3uzsoIiIi58WuMSpx9h/6Cq9c+E5SFq91w+ZzmSsYe7sp8dXgFvBQ2TGdLF3dOX+Jx2N+Ompx/flWVTGpax2nToIA82ai1z/uI0kA987s6sCIiIhKByZC5HDxD69YJEEtTRqEfiJtAUlKM2DkiiOSsiNvdUfrD3PfAT276uU88OnAZmhTw3JGWEnw6YCmUClyWSyJiIhyxd+k5HB/7p9vUZZ0N9iueyt4a7B2bOZ08Td61sWF93vh8FvdJPVGtKsuHjeu4oPI6V1KZBK04dV2+HRgUzxfyOsXERG5Ko4RygHHCBUtwWTCe2t64Dd9nKS8ZZoXdl+bk+v94SNbo3O9ijavX457jE0n72BMx5rw0rDxk4jIVXCMEDm927cOoteOMZKyd6v2Rq3KT+DZlUax7PKHvaGQy7Dwn/+gN5pgMJowpUdduzY6rV3RC1N61C302ImIqPRgIkQ4cepnlPOriTJ+1XHr7hFsPRUOd6U7hnT6AL5la8FkNODRw8soV6F+gV5nW+Q8qJRqPEqOw7sxOyXXahnlmBrREYAMGT22O6d1gjJ9HMxUJjRERFQEmAiVULExJzF664uIlguIGnoESpV7np+RlvIQF678hZeOf2r1+rJN/RAm98F2U6JY9rZ/Z3RuPgYVA5pK6p49/zsMBi2aNRkiKTfoU3Hw2DcYf+EHm3GsaLMUA1cmWZTXrOCVl7dDRESUZxwjlANnHiPU7cfGiFNIp3z7GU0I86iKJEMapnT/EgEBLWzeH755FD5/YH2RvrwY41UXVX2qYd6diDzf21tRAb+dnQaTlf8DN7zaDi2CyhQ4PiIicj15+f5mIpQDZ0yEtGnxmLX+KfxjSsi17iBNFajkKnSu9RS8PSrgyOXN+PfBKRySaXO8b5xPCHbFR+Gi3JBjvbwqZxKwoO0SnLz8B/642Ann7rtJrk/pXheXYpMwuXsd1PH3LtTXJiIi18FEqJA4UyJ05UoEBv47BYYiWPiv7q32UJQ5gvOeOnhfGYU7ujoAgPLKaFTxOInTib1gggpy6NC2/EqcrnAlT89vleKHyBtvQMihJ/apppWweHALp1/YkIiInB8ToULiLInQhn+mY+7tbRblNe+2xsn4AWjjtwYKRQouJ3RDDc9DUKke4FSFG7k+t8Gdljic8Hy+41JAh2puZ6CRJ+NmWiM8NmVdl8cElUwHveBm834A+GdqR9SuyNYfIiIqPEyEslm6dCkWLFiAmJgYNGvWDIsXL0abNm1yvc/RiZBgMuGrDc/h+8eXLK6VuTYI0Wm2xwA189oGb/fLSEqrBU9VDIwmNW6mtEIFzTWcTOoBwPY2FUuGtMDp2wn4ZvfVwngbAIDKvm4Y3q46nmxSCbcepaJV9TJcGZmIiIoEE6Es1q5di2HDhmH58uUICQnBl19+ifXr1+PixYuoWNH2YnxA0SZCWyLnIj71HmKTY7Er8TKuK8x/DIFGoIbSEwlGLU5mG6PTOLY+Tjx6FnrBDQZo8FLbanimeWVMWXsCtx6lon+LKrj3WAtBAPZevp/j6weWdYfOYMI7TzdC7yaVcC9Ji2v3k3NdbdloEnD9QTJ0BhPS9EYcuPoAANC8qh+aBvpBLgOu3U+G0SQgJiENzYP84KlWwpMLGhIRUTFhIpRFSEgIWrdujSVLlgAATCYTAgMDMWnSJMyaNSvHe4sqEbpyLRL99kzK0z1lrw7FDW0TAECLID+sHRsKtdJ2i0pcUhriErWo4K1BXKIWSoUMNcp7IjFNj4reOXdXERERlWRcWTqdTqdDVFQUZs+eLZbJ5XJ0794dBw4csKiv1Wqh1WbOqEpMTLSoUxhORD8Uj32NJvgZ5PDTeuGh22P4PWoAmcwAg9EDGvdoPExsA2//gRj+XHX0ahxg92tU9HYTEx5/n8zExy0PO7cTERGVdqU6Ebp//z6MRiP8/f0l5f7+/rhw4YJF/fnz5+Pdd98t8rj6d3wWWrdWWHskGn2bV0GTqr6QywAfNxVUCjk0KjnclArcSUhFnYreObb8EBERUf6V6kQor2bPno2pU6eK54mJiQgMLPxdvmUyGYaEBGFISFCO9cp4qgv9tYmIiChTqU6EypcvD4VCgdjYWEl5bGwsAgIsu5k0Gg00Gk1xhUdEREQOVqr7XNRqNYKDg7Fjxw6xzGQyYceOHQgNDXVgZEREROQMSnWLEABMnToVw4cPR6tWrdCmTRt8+eWXSE5OxsiRIx0dGhERETlYqU+EBg0ahHv37mHu3LmIiYlB8+bNsW3bNosB1EREROR6Sv06QgXh6JWliYiIKO/y8v1dqscIEREREeWEiRARERG5LCZCRERE5LKYCBEREZHLYiJERERELouJEBEREbksJkJERETkspgIERERkcsq9StLF0TGWpOJiYkOjoSIiIjslfG9bc+a0UyEcpCUlAQACAwMdHAkRERElFdJSUnw9fXNsQ632MiByWTCnTt34O3tDZlM5uhw8i0xMRGBgYG4efMmtwopRvzcHYOfu2Pwc3cMfu7WCYKApKQkVK5cGXJ5zqOA2CKUA7lcjqpVqzo6jELj4+PDvygOwM/dMfi5OwY/d8fg524pt5agDBwsTURERC6LiRARERG5LCZCLkCj0WDevHnQaDSODsWl8HN3DH7ujsHP3TH4uRccB0sTERGRy2KLEBEREbksJkJERETkspgIERERkctiIkREREQui4lQCTF//ny0bt0a3t7eqFixIvr164eLFy9K6qSlpWHChAkoV64cvLy8MGDAAMTGxkrqREdHo0+fPvDw8EDFihUxffp0GAwGq6+5b98+KJVKNG/evKjeltMrzs991apVaNasGTw8PFCpUiW8/PLLePDgQZG/R2dUWJ/7a6+9huDgYGg0Gqv/H0dGRqJv376oVKkSPD090bx5c6xataoo35rTKq7PHDCv+vvZZ5+hbt260Gg0qFKlCj788MOiemtOrTA+95MnT2Lw4MEIDAyEu7s7GjRogEWLFlm8VmRkJFq2bAmNRoPatWsjPDy8qN9eicBEqITYvXs3JkyYgIMHDyIiIgJ6vR49e/ZEcnKyWGfKlCnYtGkT1q9fj927d+POnTvo37+/eN1oNKJPnz7Q6XTYv38/Vq5cifDwcMydO9fi9eLj4zFs2DB069atWN6fsyquz33fvn0YNmwYRo0ahbNnz2L9+vU4fPgwxowZU6zv11kUxuee4eWXX8agQYOsvs7+/fvRtGlT/P777zh16hRGjhyJYcOGYfPmzUX23pxVcX3mAPD666/j+++/x2effYYLFy7gf//7H9q0aVMk78vZFcbnHhUVhYoVK+KXX37B2bNn8dZbb2H27NlYsmSJWOfatWvo06cPunTpghMnTmDy5MkYPXo0tm/fXqzv1ykJVCLFxcUJAITdu3cLgiAI8fHxgkqlEtavXy/WOX/+vABAOHDggCAIgrB161ZBLpcLMTExYp2vv/5a8PHxEbRareT5gwYNEubMmSPMmzdPaNasWdG/oRKiqD73BQsWCDVr1pS81ldffSVUqVKlqN9SiZCfzz2rvPx//OSTTwojR44slLhLsqL6zM+dOycolUrhwoULRRZ7SVbQzz3Dq6++KnTp0kU8nzFjhtCoUSNJnUGDBglhYWGF/A5KHrYIlVAJCQkAgLJlywIw/4tAr9eje/fuYp369esjKCgIBw4cAAAcOHAATZo0gb+/v1gnLCwMiYmJOHv2rFi2YsUKXL16FfPmzSuOt1KiFNXnHhoaips3b2Lr1q0QBAGxsbH47bff8OSTTxbXW3Nq+fncC/JaGa/jyorqM9+0aRNq1qyJzZs3o0aNGqhevTpGjx6Nhw8fFu4bKKEK63PP/v/xgQMHJM8AzL+HCvr3pTRgIlQCmUwmTJ48Ge3bt0fjxo0BADExMVCr1fDz85PU9ff3R0xMjFgn65dxxvWMawDw33//YdasWfjll1+gVHJP3qyK8nNv3749Vq1ahUGDBkGtViMgIAC+vr5YunRpEb8r55ffzz0/1q1bhyNHjmDkyJEFCbnEK8rP/OrVq7hx4wbWr1+Pn376CeHh4YiKisLAgQML8y2USIX1ue/fvx9r167F2LFjxTJbv4cSExORmppauG+khOE3XQk0YcIEnDlzBnv37i3U5xqNRgwZMgTvvvsu6tatW6jPLg2K6nMHgHPnzuH111/H3LlzERYWhrt372L69OkYN24cfvjhh0J/vZKkKD/3rHbt2oWRI0fiu+++Q6NGjYr0tZxdUX7mJpMJWq0WP/30k/h75ocffkBwcDAuXryIevXqFfprlhSF8bmfOXMGffv2xbx589CzZ89CjK70YotQCTNx4kRs3rwZu3btQtWqVcXygIAA6HQ6xMfHS+rHxsYiICBArJN9hkfGeUBAAJKSknD06FFMnDgRSqUSSqUS7733Hk6ePAmlUomdO3cW7ZtzYkX5uQPmmSPt27fH9OnT0bRpU4SFhWHZsmX48ccfcffu3SJ8Z86tIJ97XuzevRtPP/00Fi5ciGHDhhU07BKtqD/zSpUqQalUSv6x1aBBAwDm2ZWuqjA+93PnzqFbt24YO3Ys5syZI7lm6/eQj48P3N3dC/fNlDBMhEoIQRAwceJEbNiwATt37kSNGjUk14ODg6FSqbBjxw6x7OLFi4iOjkZoaCgA8ziU06dPIy4uTqwTEREBHx8fNGzYED4+Pjh9+jROnDgh/owbNw716tXDiRMnEBISUjxv1okUx+cOACkpKZDLpX8dFQqFGIOrKYzP3V6RkZHo06cPPvnkE0lXgqsprs+8ffv2MBgMuHLlilh26dIlAEC1atUK+C5KnsL63M+ePYsuXbpg+PDhVpciCA0NlTwDMP8eyuvfl1LJgQO1KQ/Gjx8v+Pr6CpGRkcLdu3fFn5SUFLHOuHHjhKCgIGHnzp3C0aNHhdDQUCE0NFS8bjAYhMaNGws9e/YUTpw4IWzbtk2oUKGCMHv2bJuv6+qzxorrc1+xYoWgVCqFZcuWCVeuXBH27t0rtGrVSmjTpk2xvl9nURifuyAIwn///SccP35ceOWVV4S6desKx48fF44fPy7O1tu5c6fg4eEhzJ49W/I6Dx48KNb36wyK6zM3Go1Cy5YthY4dOwrHjh0Tjh49KoSEhAg9evQo1vfrLArjcz99+rRQoUIF4cUXX5Q8Iy4uTqxz9epVwcPDQ5g+fbpw/vx5YenSpYJCoRC2bdtWrO/XGTERKiEAWP1ZsWKFWCc1NVV49dVXhTJlyggeHh7Cs88+K9y9e1fynOvXrwu9e/cW3N3dhfLlywvTpk0T9Hq9zdd19USoOD/3r776SmjYsKHg7u4uVKpUSRg6dKhw69at4nibTqewPvdOnTpZfc61a9cEQRCE4cOHW73eqVOn4nuzTqK4PnNBEITbt28L/fv3F7y8vAR/f39hxIgRLpl8CkLhfO7z5s2z+oxq1apJXmvXrl1C8+bNBbVaLdSsWVPyGq5MJggu2O5OREREBI4RIiIiIhfGRIiIiIhcFhMhIiIicllMhIiIiMhlMREiIiIil8VEiIiIiFwWEyEiIiJyWUyEiIiIyGUxESIiIiKXxUSIiIiIXBYTISIiInJZTISIiIjIZf0fUWgnKtOW8qcAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(fdr_data.index, kiwoom_data_adjusted_close)\n", - "plt.plot(fdr_data.index, fdr_data_adjusted_close)\n", - "plt.plot(fdr_data.index, cybos_data_adjusted_close)\n", - "\n", - "plt.legend(['kiwoom', 'fdr', 'cybos'])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "키움증권의 OpenAPI+ 와 대신증권의 CybosPlus 사이에서도 데이터 값의 차이가 발생하는 것을 확인할 수 있었다.\n", - "대신에 그 둘의 차이가 나머지 `FinancialDataReader` 케이스와의 차이보다 확연하게 적은 것을 봤을 때 `FinancialDataReader` 의 데이터가 약간은 표준에서 동떨어진 데이터가 아닐지 의심해볼 수 있겠다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 번외1. 만약에 앞에서 확인했던 Yahoo Financial 의 데이터까지 그려보면 어떻게 될까?" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
OpenHighLowCloseAdj CloseVolume
Date
2002-10-291797.7248541797.7248541797.7248541797.7248541763.381226501745
2002-10-302012.2260742012.2260741989.7545172012.2260741973.78454620892185
2002-10-312042.8691412091.8979491865.1395261912.1254881875.59631332327083
2002-11-011961.1544192022.4404301724.1815191793.6390381759.37353518373668
2002-11-041777.2961431789.5533451660.8525391703.7528081671.20434616939411
.....................
2022-01-10339000.000000339500.000000329000.000000335000.000000335000.000000828611
2022-01-11336000.000000344500.000000334500.000000335000.000000335000.000000805084
2022-01-12339500.000000352500.000000339500.000000345500.000000345500.0000001047713
2022-01-13348000.000000352000.000000344000.000000348000.000000348000.000000677226
2022-01-14341000.000000342500.000000335500.000000342000.000000342000.000000503181
\n", - "

4802 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " Open High Low Close \\\n", - "Date \n", - "2002-10-29 1797.724854 1797.724854 1797.724854 1797.724854 \n", - "2002-10-30 2012.226074 2012.226074 1989.754517 2012.226074 \n", - "2002-10-31 2042.869141 2091.897949 1865.139526 1912.125488 \n", - "2002-11-01 1961.154419 2022.440430 1724.181519 1793.639038 \n", - "2002-11-04 1777.296143 1789.553345 1660.852539 1703.752808 \n", - "... ... ... ... ... \n", - "2022-01-10 339000.000000 339500.000000 329000.000000 335000.000000 \n", - "2022-01-11 336000.000000 344500.000000 334500.000000 335000.000000 \n", - "2022-01-12 339500.000000 352500.000000 339500.000000 345500.000000 \n", - "2022-01-13 348000.000000 352000.000000 344000.000000 348000.000000 \n", - "2022-01-14 341000.000000 342500.000000 335500.000000 342000.000000 \n", - "\n", - " Adj Close Volume \n", - "Date \n", - "2002-10-29 1763.381226 501745 \n", - "2002-10-30 1973.784546 20892185 \n", - "2002-10-31 1875.596313 32327083 \n", - "2002-11-01 1759.373535 18373668 \n", - "2002-11-04 1671.204346 16939411 \n", - "... ... ... \n", - "2022-01-10 335000.000000 828611 \n", - "2022-01-11 335000.000000 805084 \n", - "2022-01-12 345500.000000 1047713 \n", - "2022-01-13 348000.000000 677226 \n", - "2022-01-14 342000.000000 503181 \n", - "\n", - "[4802 rows x 6 columns]" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "yahoo_data" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "yahoo_data_adjusted_close = yahoo_data.sort_index()['Adj Close'].reindex(fdr_data.index).to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(fdr_data.index, kiwoom_data_adjusted_close)\n", - "plt.plot(fdr_data.index, fdr_data_adjusted_close)\n", - "plt.plot(fdr_data.index, cybos_data_adjusted_close)\n", - "plt.plot(fdr_data.index, yahoo_data_adjusted_close)\n", - "\n", - "plt.legend(['kiwoom', 'fdr', 'cybos', 'yahoo'])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "무엇이 가장 올바른 수정주가일지는 아직 잘 모르겠지만, 개인적으로는 야후의 데이터도 신뢰가 간다.\n", - "야후의 데이터가 키움증권과 대신증권의 데이터의 중간즘에 있어서 더욱 그렇게 보이는 걸지도 모르겠다.\n", - "위아래의 둘도 사실은 별다른 이슈 없이 실전에 충분히 활용 가능하지 않을까 하는 생각은 든다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 번외2. 만약에 KRX 데이터를 임의로 수정주가 처리해 같이 그려보면 어떻게 될까?\n", - "\n", - "KRX 로 부터 받은 데이터를 어떻게 활용해볼 수 없을까 고민하다가 아래처럼 생각을 해보고 관련 아이디어를 적용해봤다.\n", - "\n", - "* 해당 데이터에서 Change 컬럼을 통해 당일의 주가 변동량을 확인할 수 있다.\n", - "* 당일 종가해서 당일 Change 값을 빼면 당일의 기준가를 역산해 확인할 수 있다.\n", - "* 위의 방식으로 역산한 기준가와 전일의 종가 사이에 값의 차이가 발생하는 경우 기준가가 알 수 없는 외부 영향으로 인해 인위적으로 변동이 된 것으로 생각할 수 있다.\n", - " * 일반적인 상황에서는 전일의 종가가 자연스럽게 당일의 기준가가 된다.\n", - "* 역산한 기준가와 전일 종가 사이의 비율을 통해 수정주가 비율을 추측해볼 수 있겠다고 생각이 들었다.\n", - "\n", - "다만 해당 방식을 나이브하게 여러 종목에 적용해보다가 아래와 같은 문제가 있어서 약간은 무식하게 대응한게 있는데, 구체적으로 아래와 같다.\n", - "\n", - "* KRX 데이터에서는 특정 종목이 과거에 상장폐지 후 다시 상장하는 경우 그 모든 가격 데이터가 하나의 시계열로 저장되는 경우가 있다.\n", - "* 위와 같은 경우에 상장폐지와 재 상장 사이를 위와 같은 방식으로 보정하는건 의미가 없다. 오히려 가격을 왜곡시킬 수 있다.\n", - "* 데이터상으로 확인해 봤을때 상장폐지 이력이 없는 종목들에서는 가장 긴 연휴가 11일 정도로 확인되었다. 따라서 그보다 긴 공백이 발견되면 상장폐지가 한번 되었던 종목으로 판단하고 구분해 처리한다.\n", - "\n", - "이외에 또 다른 문제가 있을지는 아직까지는 잘 모르겠다." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [], - "source": [ - "import datetime\n", - "import numpy as np\n", - "\n", - "def get_adjust_ratios(data):\n", - " data = data.sort_index(ascending=False)\n", - " adjust_ratios = []\n", - " last_close = data['Close'].iloc[0]\n", - " last_adjust_ratio = 1.0\n", - " adjust_ratios.append(last_adjust_ratio)\n", - " eleven_days = datetime.timedelta(days=11)\n", - " for i in range(data.shape[0] - 1):\n", - " if data.index[i] - data.index[i+1] > eleven_days:\n", - " last_close = data['Close'].iloc[i+1]\n", - " last_adjust_ratio = 1.0\n", - " else:\n", - " last_close = last_close - data['Change'].iloc[i] * last_adjust_ratio\n", - " last_adjust_ratio = last_close / data['Close'].iloc[i+1]\n", - " adjust_ratios.append(last_adjust_ratio)\n", - " adjust_ratios = np.array(adjust_ratios)\n", - " return adjust_ratios\n", - "\n", - "def adjust_prices(data):\n", - " data = data.sort_index(ascending=False)\n", - " adjust_ratios = get_adjust_ratios(data)\n", - " data['Adj Open'] = data['Open'] * adjust_ratios\n", - " data['Adj High'] = data['High'] * adjust_ratios\n", - " data['Adj Low'] = data['Low'] * adjust_ratios\n", - " data['Adj Close'] = data['Close'] * adjust_ratios\n", - " data['Adj Volume'] = data['Volume'] / adjust_ratios\n", - " return data" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "krx_data_adjusted = adjust_prices(krx_data)" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
CloseUpDownChangeChangeRateOpenHighLowVolumeAmountMarCapSharesAdj OpenAdj HighAdj LowAdj CloseAdj Volume
Date
2022-01-143420002-6000-1.7234100034250033550050403417110517550056104787070000164049085341000.0342500.0335500.0342000.0504034.0
2022-01-13348000125000.7234800035200034400067722623632286850657089081580000164049085348000.0352000.0344000.0348000.0677226.0
2022-01-123455001105003.13339500352500339500104513836316514050056678958867500164049085339500.0352500.0339500.0345500.01045138.0
2022-01-11335000300.0033600034450033450080508427227111902154956443475000164049085336000.0344500.0334500.0335000.0805084.0
2022-01-103350002-3000-0.8933900033950032900082861127647871750054956443475000164049085339000.0339500.0329000.0335000.0828611.0
...................................................
2002-11-04417002-2200-5.014350043800406506921652895174685031012498500074370502323.2016392339.223722170.9918772227.06915812960208.44222
2002-11-01439002-2900-6.204800049500422007507613443202605032648649500074370502563.5328432643.6432452253.7726252344.56441314057369.341543
2002-10-31468002-2450-4.9750000512004565013208806397924960034805394000074370502670.3467122734.4350332438.0265482499.44452224732368.910822
2002-10-30492504525011.934925049250487008536384203040340036627471250074370502630.2915112630.2915112600.9176972630.29151115983654.784913
2002-10-2944000422000100.004400044000440002054990415600032723020000074370502349.9051072349.9051072349.9051072349.905107384762.770841
\n", - "

4754 rows × 16 columns

\n", - "
" - ], - "text/plain": [ - " Close UpDown Change ChangeRate Open High Low \\\n", - "Date \n", - "2022-01-14 342000 2 -6000 -1.72 341000 342500 335500 \n", - "2022-01-13 348000 1 2500 0.72 348000 352000 344000 \n", - "2022-01-12 345500 1 10500 3.13 339500 352500 339500 \n", - "2022-01-11 335000 3 0 0.00 336000 344500 334500 \n", - "2022-01-10 335000 2 -3000 -0.89 339000 339500 329000 \n", - "... ... ... ... ... ... ... ... \n", - "2002-11-04 41700 2 -2200 -5.01 43500 43800 40650 \n", - "2002-11-01 43900 2 -2900 -6.20 48000 49500 42200 \n", - "2002-10-31 46800 2 -2450 -4.97 50000 51200 45650 \n", - "2002-10-30 49250 4 5250 11.93 49250 49250 48700 \n", - "2002-10-29 44000 4 22000 100.00 44000 44000 44000 \n", - "\n", - " Volume Amount MarCap Shares Adj Open \\\n", - "Date \n", - "2022-01-14 504034 171105175500 56104787070000 164049085 341000.0 \n", - "2022-01-13 677226 236322868506 57089081580000 164049085 348000.0 \n", - "2022-01-12 1045138 363165140500 56678958867500 164049085 339500.0 \n", - "2022-01-11 805084 272271119021 54956443475000 164049085 336000.0 \n", - "2022-01-10 828611 276478717500 54956443475000 164049085 339000.0 \n", - "... ... ... ... ... ... \n", - "2002-11-04 692165 28951746850 310124985000 7437050 2323.201639 \n", - "2002-11-01 750761 34432026050 326486495000 7437050 2563.532843 \n", - "2002-10-31 1320880 63979249600 348053940000 7437050 2670.346712 \n", - "2002-10-30 853638 42030403400 366274712500 7437050 2630.291511 \n", - "2002-10-29 20549 904156000 327230200000 7437050 2349.905107 \n", - "\n", - " Adj High Adj Low Adj Close Adj Volume \n", - "Date \n", - "2022-01-14 342500.0 335500.0 342000.0 504034.0 \n", - "2022-01-13 352000.0 344000.0 348000.0 677226.0 \n", - "2022-01-12 352500.0 339500.0 345500.0 1045138.0 \n", - "2022-01-11 344500.0 334500.0 335000.0 805084.0 \n", - "2022-01-10 339500.0 329000.0 335000.0 828611.0 \n", - "... ... ... ... ... \n", - "2002-11-04 2339.22372 2170.991877 2227.069158 12960208.44222 \n", - "2002-11-01 2643.643245 2253.772625 2344.564413 14057369.341543 \n", - "2002-10-31 2734.435033 2438.026548 2499.444522 24732368.910822 \n", - "2002-10-30 2630.291511 2600.917697 2630.291511 15983654.784913 \n", - "2002-10-29 2349.905107 2349.905107 2349.905107 384762.770841 \n", - "\n", - "[4754 rows x 16 columns]" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "krx_data_adjusted" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "krx_data_adjusted_close = krx_data_adjusted.sort_index()['Adj Close'].reindex(fdr_data.index).to_numpy()" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAGdCAYAAAD+JxxnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAA9hAAAPYQGoP6dpAACDIElEQVR4nO3dd3QU1d8G8Gd7eqEkoSSEnlADoYXeJCL6ioKiqBRBRUGliIAoWH42RCkCYqMJCKIiVRAIQek1SAkBIRBaCpDets37x5JJJrubQspuss/nnBxn7r0zc3cC7pdbZYIgCCAiIiJyQHJbV4CIiIjIVhgIERERkcNiIEREREQOi4EQEREROSwGQkREROSwGAgRERGRw2IgRERERA6LgRARERE5LKWtK2DPjEYjbt26BXd3d8hkMltXh4iIiEpAEASkp6ejbt26kMuLbvNhIFSEW7duwd/f39bVICIiogdw/fp11K9fv8gyDISK4O7uDsD0Ij08PGxcGyIiIiqJtLQ0+Pv7i9/jRWEgVIS87jAPDw8GQkRERFVMSYa1cLA0EREROSwGQkREROSwGAgRERGRw+IYoTISBAF6vR4Gg8HWVaH7FAoFlEollzwgIqJiMRAqA61Wi9u3byMrK8vWVaFCXFxcUKdOHajValtXhYiI7BgDoQdkNBoRGxsLhUKBunXrQq1WswXCDgiCAK1Wi6SkJMTGxqJp06bFLqZFRESOi4HQA9JqtTAajfD394eLi4utq0MFODs7Q6VS4dq1a9BqtXBycrJ1lYiIyE7xn8plxNYG+8TfCxERlQS/LYiIiMhhMRAiIiIih8VAyAH17t0bEydOtJg3atQoDB48uFLrQ0REZCscLE0SCxYsgCAItq4GERFRpWCLEEl4enrCy8vL1tUgIqIq7sSeP7Fs3Ez8d/q4ratSJAZC5UgQBGRp9Tb5KUsrzrZt2+Dp6Yk1a9ZIusa2bt0KLy8vcdXsqKgoyGQyTJ8+Xbx27NixeP7558Xz3377DS1btoRGo0FgYCC+/PJLybOSk5MxYsQIeHt7w8XFBQMHDsSlS5fE/BUrVsDLywtbt25F8+bN4eLigqFDhyIrKwsrV65EYGAgvL298cYbb3A1byIiO5R4/Rr0Oh1OrMlCNvph37xdtq5Skdg1Vo6ydQa0mLXTJs8+/2E4XNSl/3WuXbsW48aNw9q1a/Hoo49i1678P7A9evRAeno6Tp06hQ4dOmDfvn2oVasWIiMjxTL79u3DtGnTAAAnTpzA008/jffffx/Dhg3DwYMH8dprr6FmzZoYNWoUANMYpEuXLmHz5s3w8PDAtGnT8Mgjj+D8+fNQqVQAgKysLCxcuBDr1q1Deno6nnzySTzxxBPw8vLC9u3bceXKFQwZMgTdunXDsGHDHvylERFRufrl4//hzrVO0OSuhc65MwBAQICNa1U0BkIObPHixZg5cya2bNmCXr16meV7enoiJCQEkZGR6NChAyIjIzFp0iR88MEHyMjIQGpqKv777z/x2q+++gr9+vXDe++9BwBo1qwZzp8/jy+++EISAB04cABdu3YFAKxZswb+/v74448/8NRTTwEAdDodvvnmGzRu3BgAMHToUPz0009ISEiAm5sbWrRogT59+mDv3r0MhIiI7Eh6jDsEFyVy7gdBAABBZ7sKlQADoXLkrFLg/IfhNnt2afz6669ITEzEgQMH0LFjR6vlevXqhcjISEyZMgX//PMPPv30U/zyyy/Yv38/7t27h7p166Jp06YAgOjoaDz++OOS67t164b58+fDYDAgOjoaSqUSnTvn/wWpWbMmmjdvjujoaDHNxcVFDIIAwNfXF4GBgXBzc5OkJSYmluozExFRxcpxaW3rKpQaA6FyJJPJHqh7yhbatWuHkydPYtmyZejQoYPVfdJ69+6NZcuW4fTp01CpVAgKCkLv3r0RGRmJ5ORkiy1JZZXXRZZHJpNZTDMajeX+bCIiejB6nbWWH/ueiczB0g6qcePG2Lt3LzZt2oTXX3/darm8cULz5s0Tg568QCgyMhK9e/cWywYHB+PAgQOS6w8cOIBmzZpBoVAgODgYer0eR44cEfPv3r2LmJgYtGjRonw/IBERVSqdVmslx743JGcg5MCaNWuGvXv34rfffrO6wKK3tzfatGmDNWvWiEFPz549cfLkSVy8eFHSIjRlyhTs2bMHH330ES5evIiVK1di0aJFeOuttwAATZs2xeOPP46XXnoJ+/fvx+nTp/H888+jXr16Zl1qRERUtWhzsq3k2HeoUTX6cajCNG/eHBEREejduzcUCsvjjHr16oWoqCgxEKpRowZatGiBhIQENG/eXCzXvn17/PLLL5g1axY++ugj1KlTBx9++KE4YwwAli9fjjfffBOPPvootFotevbs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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(fdr_data.index, kiwoom_data_adjusted_close)\n", - "plt.plot(fdr_data.index, fdr_data_adjusted_close)\n", - "plt.plot(fdr_data.index, cybos_data_adjusted_close)\n", - "plt.plot(fdr_data.index, yahoo_data_adjusted_close)\n", - "plt.plot(fdr_data.index, krx_data_adjusted_close)\n", - "\n", - "plt.legend(['kiwoom', 'fdr', 'cybos', 'yahoo', 'krx'])\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "놀랍게도 수정한 KRX 데이터가 앞서 대신증권 Cybos Plus 를 활용해 받은 수정주가 데이터를 거의 가려버리는 형국으로 보인다.\n", - "아마도 대신증권에서는 수정주가 계산시 내가 위에서 생각해낸 아이디어와 거의 비슷한 방향으로 접근하고 있는건 아닐지 조심스레 추측해본다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6. 그래서 과거 주식 가격 데이터를 지속적으로 업데이트 하는데에 있어서 가장 좋은 방법은 뭘까?\n", - "\n", - "일단 당장 자신있게 내릴 수 있는 결론 하나는 다음과 같다.\n", - "\n", - "> 아래의 조건에 만족하는 경우 KRX 의 데이터를 활용한다.\n", - "> * 수정주가는 필요없다.\n", - "> * 일봉보다 작은 타임프레임의 가격 데이터는 필요없다.\n", - "\n", - "그 다음으로 아래도 생각해볼 수 있겠다.\n", - "\n", - "> 아래의 조건에 만족하는 경우 Yahoo Finance 의 데이터를 활용한다.\n", - "> * 일봉보다 작은 타임프레임의 가격 데이터는 필요없지만 수정주가는 필요하다.\n", - "> * 증권사 API 를 사용하는건 너무 번거로운 것 같다.\n", - "\n", - "당장 Yahoo Finance 를 사용하지 말아야 할 이유는 떠오르지 않지만, 만약에 Yahoo Finance 는 싫은데 일봉 단위 수정주가가 필요한 경우, 차선책으로 KRX 데이터로부터 직접 수정주가를 생성하는 방식도 어느정도 유효하지 않을까 싶은 생각이다. 이 경우 자신이 직접 수정주가를 처리하는 것에 대한 리스크는 어느정도 감수해야 한다. (개인적으로 그리 크게 리스크가 있을 것 같지는 않다는 생각이다.)\n", - "\n", - "> 아래의 조건에 만족하는 경우 KRX 의 데이터에 기반해 직접 수정주가 처리를 해서 활용한다.\n", - "> * 일봉보다 작은 타임프레임의 가격 데이터는 필요없지만 수정주가는 필요하다.\n", - "> * 증권사 API 를 사용하는건 너무 번거로운 것 같다.\n", - "> * 수정주가 처리방식을 내가 직접 관리하고 싶다.\n", - "> * 왠지 Yahoo Finance 는 쓰기 싫다.\n", - "\n", - "이외에 일봉보다 작은 타임프레임의 영역으로 들어가게 되면 결국 증권사 API 의 사용은 필수가 된다. 수정주가의 경우는 제공 안하는 증권사를 찾는게 더 어렵지 않을까 싶다.\n", - "\n", - "여기서 고려했던 두 증권사 API 말고도 다른 다양한 API 가 있겠지만, 먼저 고려했던 둘 중에 하나를 고르자면, 적어도 주식 가격데이터 확보의 관점에서는, 개인적으로 대신증권의 Cybos Plus 를 권하고 싶다. 구체적인 이유는 다음과 같다.\n", - "\n", - "1. Cybos Plus 가 속도 측면에서 압도적으로 빠르다.\n", - " * 모든 증권사 API 는 과도한 요청을 제한하기 위해 시간당 API 요청 횟수의 제한을 두는데 상대적으로 Cybos Plus 가 훨씬 느슨하게 제한을 하고 있다.\n", - " * 키움증권의 OpenAPI+ 의 경우 표면적으로 1초당 5회라고 이야기하고 있지만 내부적으로는 길게 봤을때 1시간당 1000회로, 거의 4초당 1회 꼴로 제한을 두고 있다.\n", - " * 그러면서 1회 호출마다 확보 가능한 레코드 수는 600건 정도에 불과하다.\n", - " * 일봉 데이터 기준 단순 속도를 계산해보면 **150일/초** 정도가 된다. \n", - " * 반면에 대신증권의 Cybos Plus 는 단순하게 15초에 60회, 나눠보면 1초에 4회 정도까지 호출이 가능하다.\n", - " * Cybos Plus 는 요청시에 필요한 컬럼들만 가져오도록 설정이 가능하다.\n", - " * Cybos Plus 는 1회 요청에서 결과 테이블 내 전체 셀 개수의 총량을 제한하는 식으로 트래픽을 조절하고 있다.\n", - " * 위의 두가지 성격으로 인해 1회 호출시에 확보 가능한 레코드 수는 요청하는 컬럼수에 반비례하게 된다.\n", - " * 따라서 정말 필요한 컬럼들로만 제한해 호출하는 경우 속도는 더욱 빨라질 수 있다.\n", - " * 일반적인 컬럼들로 설정했다고 가정했을때 1회 호출마다 대략 2000건의 레코드를 받을 수 있다.\n", - " * 일봉 데이터 기준 단순 속도를 계산해보면 **8000일/초** 정도가 된다. 대략 키움증권 OpenAPI+ 의 **50배**가 되는 속도이다.\n", - "2. Cybos Plus 가 지원하는 확인 가능한 과거 데이터의 기간도 더 길다.\n", - " * 더 과거의 데이터를 확인할 수 있다는 의미다.\n", - " * 만약에 최대한 많은 데이터를 확보하려는 입장이라면 유의미한 차이로 볼 수 있다.\n", - "3. 요청시에 필요한 컬럼들만 가져오도록 설정 가능한 부분이 유용하게 사용될 수 있다. 예를 들어 아래와 같은 구성이 가능하다.\n", - " 1. 일별 타임프레임하에 수정주가비율 관련 정보만 요청해 주기적으로 업데이트 한다.\n", - " * 수정주가가 하루 단위보다 더 잘게 나뉘어서 적용되지는 않기 때문에 일별 타임프레임으로 저장하면 된다.\n", - " * 해당 정보는 매번 전체 업데이트를 거쳐도 된다. 필요한 컬럼만 요청하기 때문에 비교적 빠르게 값을 갱신하는 것이 가능하다.\n", - " * 주기적으로 업데이트 처리를 하는게 가능하다면 효율성 측면에서 아래처럼 처리할 수도 있어 보인다.\n", - " 1. 업데이트시 현재 로컬에 가지고 있는 데이터 기준으로 가장 최근의 영업일과 중복되는/겹쳐지는 결과가 되도록 기간을 설정해 API 를 통해 수정주가비율을 요청한다.\n", - " * 매일 업데이트 하는 경우 기간을 최근 2영업일로 설정해 요청하면 된다.\n", - " 2. 겹치게 되는 영업일의 수정주가비율에서 차이가 발생하게 되면 전체 기간에 대한 업데이트를 진행한다.\n", - " * 만약에 차이가 없으면 겹치는 날짜를 제외한 나머지 신규 데이터만 추가한다.\n", - " * 차이가 발생하는 경우의 기존 과거기간 전체에 대한 업데이트는 아래와 같은 방식으로도 가능하다.\n", - " 1. 겹치는 영업일에서 기존/신규 수정주가비율 사이의 값의 차이를 비율 형태로 확인한다.\n", - " 2. 기존에 가지고 있던 과거 수정주가비율 전체를 해당 비율만큼 동일하게 조정해준다.\n", - " * 겹치게 되는 영업일에서 기존 로컬의 수정주가비율이 요청을 통해 받은 신규 수정주가비율 만큼 되도록 조정해주는 것으로 보면 된다.\n", - " 2. 다른 필요한 주식 가격 데이터들은 모두 수정주가를 적용하지 않은 버전으로 가져와 로컬에 저장한다.\n", - " * 이 경우 매번 전체 데이터를 업데이트 할 필요 없이 누락된 최신 데이터만 추가로 요청해 덧붙이는 식으로 업데이트가 가능하다.\n", - " 3. 이후 수정주가가 필요할때마다 아래와 같이 처리해 사용한다.\n", - " 1. 원본주가 데이터를 먼저 로드한다.\n", - " 2. 일별 주가수정비율 데이터도 같이 로드한다.\n", - " 3. 날짜 기준으로 위의 두 데이터를 조인 후 주가수정비율에 맞게 각 가격의 값을 조정한다.\n", - " \n", - "증권사 API 선택방식과 관련해서 정리하자면 아래처럼 될 수 있겠다.\n", - "\n", - "> 아래의 조건에 만족하는 경우 대신증권 Cybos Plus 의 데이터를 활용한다.\n", - "> * 분봉 이하를 포함한 다양한 타임프레임의 가격 데이터가 필요하다.\n", - "> * 데이터 업데이트를 효율적으로 하고 싶다.\n", - "> * 더 많은 기간의 데이터를 확보하는 것이 중요하다.\n", - "\n", - "> 아래의 조건에 만족하는 경우 키움증권 OpenAPI+ 의 데이터를 활용한다.\n", - "> * 분봉 이하를 포함한 다양한 타임프레임의 가격 데이터가 필요하다.\n", - "> * 업데이트 속도나 효율성은 크게 중요하지 않다.\n", - "> * 확보 가능한 과거 데이터의 기간도 크게 중요하지 않다.\n", - "> * 여러 증권사 API 를 사용하는게 번거로울 것 같다. 나는 원래 쓰던 키움증권만 쓰련다.\n", - "\n", - "각 증권사마다 수정주가 계산을 다르게 처리하는 것과 관련해서는, 필요하다면 각기 증권사에 문의해본 뒤에 자신에게 맞는 방식을 골라서 사용하면 되지 않을지 하는 생각이다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cybos Plus 를 활용한 수정주가 별도 관리 방식의 구체적인 예시\n", - "\n", - "위의 Cybos Plus 의 장점을 설명하는 내용중 마지막 3번에서 설명했던 방식을 좀 더 구체적인 예시를 들어보자면 아래와 같다." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:00:53,864 [DEBUG] Requesting from 2022-01-14 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:53,915 [DEBUG] Requested 6666, received 4754 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:53,955 [DEBUG] Received data from 2022-01-14 00:00:00+09:00 to 2002-10-29 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:53,955 [DEBUG] No more data to request - CybosPlusEntrypointMixin.py:454\n" - ] - } - ], - "source": [ - "adjustment_ratios = cybos_entrypoint.GetDailyAdjustmentRatioAsDataFrame(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
날짜수정주가일자수정주가비율
02022011420220114100.00
12022011320220113100.00
22022011220220112100.00
32022011120220111100.00
42022011020220110100.00
............
474920021104200211045.24
475020021101200211015.24
475120021031200210315.24
475220021030200210305.24
475320021029200210295.24
\n", - "

4754 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " 날짜 수정주가일자 수정주가비율\n", - "0 20220114 20220114 100.00\n", - "1 20220113 20220113 100.00\n", - "2 20220112 20220112 100.00\n", - "3 20220111 20220111 100.00\n", - "4 20220110 20220110 100.00\n", - "... ... ... ...\n", - "4749 20021104 20021104 5.24\n", - "4750 20021101 20021101 5.24\n", - "4751 20021031 20021031 5.24\n", - "4752 20021030 20021030 5.24\n", - "4753 20021029 20021029 5.24\n", - "\n", - "[4754 rows x 3 columns]" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "adjustment_ratios" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:00:53,984 [DEBUG] Requesting from 2022-01-14 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,064 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,116 [DEBUG] Received data from 2022-01-14 00:00:00+09:00 to 2021-08-25 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,117 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,124 [DEBUG] Trailing rows truncated: 7 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,125 [DEBUG] Requesting from 2021-08-25 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,197 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,250 [DEBUG] Received data from 2021-08-25 00:00:00+09:00 to 2021-04-08 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,250 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,255 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,256 [DEBUG] Requesting from 2021-04-08 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,322 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,375 [DEBUG] Received data from 2021-04-08 00:00:00+09:00 to 2020-11-17 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,376 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,381 [DEBUG] Trailing rows truncated: 7 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,381 [DEBUG] Requesting from 2020-11-17 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,447 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,499 [DEBUG] Received data from 2020-11-17 00:00:00+09:00 to 2020-06-29 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,500 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,505 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,506 [DEBUG] Requesting from 2020-06-29 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,572 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,627 [DEBUG] Received data from 2020-06-29 00:00:00+09:00 to 2020-02-10 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,628 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,632 [DEBUG] Trailing rows truncated: 5 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,633 [DEBUG] Requesting from 2020-02-10 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,708 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,761 [DEBUG] Received data from 2020-02-10 00:00:00+09:00 to 2019-09-18 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,761 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,766 [DEBUG] Trailing rows truncated: 7 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,767 [DEBUG] Requesting from 2019-09-18 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,836 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:54,888 [DEBUG] Received data from 2019-09-18 00:00:00+09:00 to 2019-04-29 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:54,889 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:54,893 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:54,894 [DEBUG] Requesting from 2019-04-29 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:54,972 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,037 [DEBUG] Received data from 2019-04-29 00:00:00+09:00 to 2018-12-05 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,038 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:55,043 [DEBUG] Trailing rows truncated: 7 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:55,043 [DEBUG] Requesting from 2018-12-05 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:55,105 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,160 [DEBUG] Received data from 2018-12-05 00:00:00+09:00 to 2018-07-11 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,160 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:55,165 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:55,165 [DEBUG] Requesting from 2018-07-11 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:55,235 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,287 [DEBUG] Received data from 2018-07-11 00:00:00+09:00 to 2018-02-19 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,288 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:55,293 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:55,293 [DEBUG] Requesting from 2018-02-19 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:55,355 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,407 [DEBUG] Received data from 2018-02-19 00:00:00+09:00 to 2017-09-21 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,408 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:55,412 [DEBUG] Trailing rows truncated: 7 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:55,413 [DEBUG] Requesting from 2017-09-21 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:55,480 [DEBUG] Requested 2500, received 2499 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,532 [DEBUG] Received data from 2017-09-21 00:00:00+09:00 to 2017-05-04 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,533 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:00:55,537 [DEBUG] Trailing rows truncated: 3 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:00:55,538 [DEBUG] Requesting from 2017-05-04 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:00:55,606 [DEBUG] Requested 2500, received 2492 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:00:55,659 [DEBUG] Received data from 2017-05-04 00:00:00+09:00 to 2016-12-14 00:00:00+09:00 for code A035420 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:00:55,660 [DEBUG] No more data to request - CybosPlusEntrypointMixin.py:454\n" - ] - } - ], - "source": [ - "minutes_data = cybos_entrypoint.GetMinuteStockDataAsDataFrame(code, 15)" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
날짜시간시가고가저가종가거래량거래대금
02022011415303425003425003415003420003777812919230000
1202201141515341000342500341000342000238618150870000
2202201141500340000341500340000341000186146342730000
320220114144534050034100034000034050097173306250000
4202201141430341000341500340000340500116573970570000
...........................
3241720161214101579000079000078500078500020951651290000
324182016121410007920007920007890007890001124888470000
324192016121494579200079200078800079200019791563680000
324202016121493079500079500079100079200013811094780000
324212016121491579300079600079100079500038493053210000
\n", - "

32422 rows × 8 columns

\n", - "
" - ], - "text/plain": [ - " 날짜 시간 시가 고가 저가 종가 거래량 거래대금\n", - "0 20220114 1530 342500 342500 341500 342000 37778 12919230000\n", - "1 20220114 1515 341000 342500 341000 342000 23861 8150870000\n", - "2 20220114 1500 340000 341500 340000 341000 18614 6342730000\n", - "3 20220114 1445 340500 341000 340000 340500 9717 3306250000\n", - "4 20220114 1430 341000 341500 340000 340500 11657 3970570000\n", - "... ... ... ... ... ... ... ... ...\n", - "32417 20161214 1015 790000 790000 785000 785000 2095 1651290000\n", - "32418 20161214 1000 792000 792000 789000 789000 1124 888470000\n", - "32419 20161214 945 792000 792000 788000 792000 1979 1563680000\n", - "32420 20161214 930 795000 795000 791000 792000 1381 1094780000\n", - "32421 20161214 915 793000 796000 791000 795000 3849 3053210000\n", - "\n", - "[32422 rows x 8 columns]" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "minutes_data" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [], - "source": [ - "adjusted_minutes_data = pd.merge(minutes_data, adjustment_ratios, on='날짜', how='left')" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
날짜시간시가고가저가종가거래량거래대금수정주가일자수정주가비율
0202201141530342500342500341500342000377781291923000020220114100.0
120220114151534100034250034100034200023861815087000020220114100.0
220220114150034000034150034000034100018614634273000020220114100.0
32022011414453405003410003400003405009717330625000020220114100.0
420220114143034100034150034000034050011657397057000020220114100.0
.................................
32417201612141015790000790000785000785000209516512900002016121420.0
3241820161214100079200079200078900078900011248884700002016121420.0
3241920161214945792000792000788000792000197915636800002016121420.0
3242020161214930795000795000791000792000138110947800002016121420.0
3242120161214915793000796000791000795000384930532100002016121420.0
\n", - "

32422 rows × 10 columns

\n", - "
" - ], - "text/plain": [ - " 날짜 시간 시가 고가 저가 종가 거래량 거래대금 \\\n", - "0 20220114 1530 342500 342500 341500 342000 37778 12919230000 \n", - "1 20220114 1515 341000 342500 341000 342000 23861 8150870000 \n", - "2 20220114 1500 340000 341500 340000 341000 18614 6342730000 \n", - "3 20220114 1445 340500 341000 340000 340500 9717 3306250000 \n", - "4 20220114 1430 341000 341500 340000 340500 11657 3970570000 \n", - "... ... ... ... ... ... ... ... ... \n", - "32417 20161214 1015 790000 790000 785000 785000 2095 1651290000 \n", - "32418 20161214 1000 792000 792000 789000 789000 1124 888470000 \n", - "32419 20161214 945 792000 792000 788000 792000 1979 1563680000 \n", - "32420 20161214 930 795000 795000 791000 792000 1381 1094780000 \n", - "32421 20161214 915 793000 796000 791000 795000 3849 3053210000 \n", - "\n", - " 수정주가일자 수정주가비율 \n", - "0 20220114 100.0 \n", - "1 20220114 100.0 \n", - "2 20220114 100.0 \n", - "3 20220114 100.0 \n", - "4 20220114 100.0 \n", - "... ... ... \n", - "32417 20161214 20.0 \n", - "32418 20161214 20.0 \n", - "32419 20161214 20.0 \n", - "32420 20161214 20.0 \n", - "32421 20161214 20.0 \n", - "\n", - "[32422 rows x 10 columns]" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "adjusted_minutes_data" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "price_multiplier = adjusted_minutes_data['수정주가비율'] / 100" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 1.0\n", - "1 1.0\n", - "2 1.0\n", - "3 1.0\n", - "4 1.0\n", - " ... \n", - "32417 0.2\n", - "32418 0.2\n", - "32419 0.2\n", - "32420 0.2\n", - "32421 0.2\n", - "Name: 수정주가비율, Length: 32422, dtype: float64" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "price_multiplier" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [], - "source": [ - "adjusted_minutes_data['수정시가'] = adjusted_minutes_data['시가'] * price_multiplier\n", - "adjusted_minutes_data['수정고가'] = adjusted_minutes_data['고가'] * price_multiplier\n", - "adjusted_minutes_data['수정저가'] = adjusted_minutes_data['저가'] * price_multiplier\n", - "adjusted_minutes_data['수정종가'] = adjusted_minutes_data['종가'] * price_multiplier\n", - "adjusted_minutes_data['수정거래량'] = adjusted_minutes_data['거래량'] / price_multiplier" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
날짜시간시가고가저가종가거래량거래대금수정주가일자수정주가비율수정시가수정고가수정저가수정종가수정거래량
0202201141530342500342500341500342000377781291923000020220114100.0342500.0342500.0341500.0342000.037778.0
120220114151534100034250034100034200023861815087000020220114100.0341000.0342500.0341000.0342000.023861.0
220220114150034000034150034000034100018614634273000020220114100.0340000.0341500.0340000.0341000.018614.0
32022011414453405003410003400003405009717330625000020220114100.0340500.0341000.0340000.0340500.09717.0
420220114143034100034150034000034050011657397057000020220114100.0341000.0341500.0340000.0340500.011657.0
................................................
32417201612141015790000790000785000785000209516512900002016121420.0158000.0158000.0157000.0157000.010475.0
3241820161214100079200079200078900078900011248884700002016121420.0158400.0158400.0157800.0157800.05620.0
3241920161214945792000792000788000792000197915636800002016121420.0158400.0158400.0157600.0158400.09895.0
3242020161214930795000795000791000792000138110947800002016121420.0159000.0159000.0158200.0158400.06905.0
3242120161214915793000796000791000795000384930532100002016121420.0158600.0159200.0158200.0159000.019245.0
\n", - "

32422 rows × 15 columns

\n", - "
" - ], - "text/plain": [ - " 날짜 시간 시가 고가 저가 종가 거래량 거래대금 \\\n", - "0 20220114 1530 342500 342500 341500 342000 37778 12919230000 \n", - "1 20220114 1515 341000 342500 341000 342000 23861 8150870000 \n", - "2 20220114 1500 340000 341500 340000 341000 18614 6342730000 \n", - "3 20220114 1445 340500 341000 340000 340500 9717 3306250000 \n", - "4 20220114 1430 341000 341500 340000 340500 11657 3970570000 \n", - "... ... ... ... ... ... ... ... ... \n", - "32417 20161214 1015 790000 790000 785000 785000 2095 1651290000 \n", - "32418 20161214 1000 792000 792000 789000 789000 1124 888470000 \n", - "32419 20161214 945 792000 792000 788000 792000 1979 1563680000 \n", - "32420 20161214 930 795000 795000 791000 792000 1381 1094780000 \n", - "32421 20161214 915 793000 796000 791000 795000 3849 3053210000 \n", - "\n", - " 수정주가일자 수정주가비율 수정시가 수정고가 수정저가 수정종가 수정거래량 \n", - "0 20220114 100.0 342500.0 342500.0 341500.0 342000.0 37778.0 \n", - "1 20220114 100.0 341000.0 342500.0 341000.0 342000.0 23861.0 \n", - "2 20220114 100.0 340000.0 341500.0 340000.0 341000.0 18614.0 \n", - "3 20220114 100.0 340500.0 341000.0 340000.0 340500.0 9717.0 \n", - "4 20220114 100.0 341000.0 341500.0 340000.0 340500.0 11657.0 \n", - "... ... ... ... ... ... ... ... \n", - "32417 20161214 20.0 158000.0 158000.0 157000.0 157000.0 10475.0 \n", - "32418 20161214 20.0 158400.0 158400.0 157800.0 157800.0 5620.0 \n", - "32419 20161214 20.0 158400.0 158400.0 157600.0 158400.0 9895.0 \n", - "32420 20161214 20.0 159000.0 159000.0 158200.0 158400.0 6905.0 \n", - "32421 20161214 20.0 158600.0 159200.0 158200.0 159000.0 19245.0 \n", - "\n", - "[32422 rows x 15 columns]" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "adjusted_minutes_data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 데이터 소스별 지원 기간 비교\n", - "\n", - "위에서 검토해본 데이터 소스들에서 제공 가능한 가장 오래된 데이터의 범위가 어디까지인지 비교해본다. " - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [], - "source": [ - "code = '005930'" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "fdr_data = fdr.DataReader(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "yahoo_data = yahoo_downloader.download(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "krx_data = krx_downloader.download(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:01:05,383 [DEBUG] Received 600 records from 2022-01-14 00:00:00 to 2019-08-13 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:05,668 [DEBUG] Received 600 records from 2019-08-12 00:00:00 to 2017-02-28 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:05,977 [DEBUG] Received 600 records from 2017-02-27 00:00:00 to 2014-09-24 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:06,274 [DEBUG] Received 600 records from 2014-09-23 00:00:00 to 2012-04-18 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:06,568 [DEBUG] Received 600 records from 2012-04-17 00:00:00 to 2009-11-20 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:23,394 [DEBUG] Received 600 records from 2009-11-19 00:00:00 to 2007-06-25 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:23,691 [DEBUG] Received 600 records from 2007-06-22 00:00:00 to 2005-01-24 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:23,988 [DEBUG] Received 600 records from 2005-01-21 00:00:00 to 2002-08-22 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:24,289 [DEBUG] Received 600 records from 2002-08-21 00:00:00 to 2000-03-06 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:24,587 [DEBUG] Received 600 records from 2000-03-03 00:00:00 to 1997-12-06 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:41,415 [DEBUG] Received 600 records from 1997-12-05 00:00:00 to 1995-11-20 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:41,713 [DEBUG] Received 600 records from 1995-11-18 00:00:00 to 1993-11-08 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:42,008 [DEBUG] Received 600 records from 1993-11-06 00:00:00 to 1991-10-25 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:42,311 [DEBUG] Received 600 records from 1991-10-24 00:00:00 to 1989-10-04 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:42,627 [DEBUG] Received 600 records from 1989-09-30 00:00:00 to 1987-09-07 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:59,380 [DEBUG] Received 600 records from 1987-09-05 00:00:00 to 1985-08-23 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n", - "2022-01-14 17:01:59,530 [DEBUG] Received 190 records from 1985-08-22 00:00:00 to 1985-01-04 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:571\n" - ] - } - ], - "source": [ - "kiwoom_data = kiwoom_entrypoint.GetDailyStockDataAsDataFrame(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-14 17:01:59,566 [DEBUG] Requesting from 2022-01-14 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:01:59,622 [DEBUG] Requested 2857, received 2856 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:01:59,681 [DEBUG] Received data from 2022-01-14 00:00:00+09:00 to 2010-06-22 00:00:00+09:00 for code A005930 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:01:59,681 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:01:59,687 [DEBUG] Trailing rows truncated: 1 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:01:59,688 [DEBUG] Requesting from 2010-06-22 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:01:59,738 [DEBUG] Requested 2857, received 2856 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:01:59,793 [DEBUG] Received data from 2010-06-22 00:00:00+09:00 to 1998-12-01 00:00:00+09:00 for code A005930 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:01:59,793 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:01:59,799 [DEBUG] Trailing rows truncated: 1 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:01:59,799 [DEBUG] Requesting from 1998-12-01 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:01:59,849 [DEBUG] Requested 2857, received 2856 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:01:59,901 [DEBUG] Received data from 1998-12-01 00:00:00+09:00 to 1989-03-11 00:00:00+09:00 for code A005930 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:01:59,902 [DEBUG] More data to request remains - CybosPlusEntrypointMixin.py:439\n", - "2022-01-14 17:01:59,907 [DEBUG] Trailing rows truncated: 1 - CybosPlusEntrypointMixin.py:449\n", - "2022-01-14 17:01:59,908 [DEBUG] Requesting from 1989-03-11 00:00:00+09:00 - CybosPlusEntrypointMixin.py:395\n", - "2022-01-14 17:02:00,001 [DEBUG] Requested 2857, received 2691 records - CybosPlusEntrypointMixin.py:399\n", - "2022-01-14 17:02:00,050 [DEBUG] Received data from 1989-03-11 00:00:00+09:00 to 1980-01-04 00:00:00+09:00 for code A005930 - CybosPlusEntrypointMixin.py:426\n", - "2022-01-14 17:02:00,051 [DEBUG] No more data to request - CybosPlusEntrypointMixin.py:454\n" - ] - } - ], - "source": [ - "cybos_data = cybos_entrypoint.GetDailyStockDataAsDataFrame(code)" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [], - "source": [ - "data = [\n", - " fdr_data.index.to_series().describe(datetime_is_numeric=True),\n", - " yahoo_data.index.to_series().describe(datetime_is_numeric=True),\n", - " krx_data.index.to_series().describe(datetime_is_numeric=True),\n", - " pd.to_datetime(kiwoom_data['일자'], format='%Y%m%d').describe(datetime_is_numeric=True),\n", - " pd.to_datetime(cybos_data['날짜'], format='%Y%m%d').describe(datetime_is_numeric=True), \n", - "]\n", - "keys = ['fdr', 'yahoo', 'krx', 'kiwoom', 'cybos']\n", - "result = pd.concat(data, axis=1, keys=keys).T" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
countmeanmin25%50%75%max
fdr60002009-11-24 17:10:33.6000000001997-12-062003-11-09 06:00:002009-11-19 12:00:002015-12-08 06:00:002022-01-14
yahoo55372010-11-19 17:02:35.3910059522000-01-042005-04-25 00:00:002010-10-22 00:00:002016-05-27 00:00:002022-01-14
krx67652008-05-25 16:44:16.4966740481995-05-022001-07-09 00:00:002008-05-16 00:00:002015-03-05 00:00:002022-01-14
kiwoom97902002-10-07 12:12:21.3278854401985-01-041993-05-19 06:00:002002-04-01 12:00:002012-02-07 18:00:002022-01-14
cybos112562000-02-16 10:05:45.4157781761980-01-041989-08-08 18:00:001999-04-07 12:00:002010-08-18 06:00:002022-01-14
\n", - "
" - ], - "text/plain": [ - " count mean min 25% \\\n", - "fdr 6000 2009-11-24 17:10:33.600000000 1997-12-06 2003-11-09 06:00:00 \n", - "yahoo 5537 2010-11-19 17:02:35.391005952 2000-01-04 2005-04-25 00:00:00 \n", - "krx 6765 2008-05-25 16:44:16.496674048 1995-05-02 2001-07-09 00:00:00 \n", - "kiwoom 9790 2002-10-07 12:12:21.327885440 1985-01-04 1993-05-19 06:00:00 \n", - "cybos 11256 2000-02-16 10:05:45.415778176 1980-01-04 1989-08-08 18:00:00 \n", - "\n", - " 50% 75% max \n", - "fdr 2009-11-19 12:00:00 2015-12-08 06:00:00 2022-01-14 \n", - "yahoo 2010-10-22 00:00:00 2016-05-27 00:00:00 2022-01-14 \n", - "krx 2008-05-16 00:00:00 2015-03-05 00:00:00 2022-01-14 \n", - "kiwoom 2002-04-01 12:00:00 2012-02-07 18:00:00 2022-01-14 \n", - "cybos 1999-04-07 12:00:00 2010-08-18 06:00:00 2022-01-14 " - ] - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "result" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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cgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABjJ7ZFz9uxZPfvss4qIiFC1atV01VVX6bnnnlNpaam1prS0VImJiQoNDVW1atUUFRWlPXv2uNzPkSNHFBMTI4fDocDAQMXGxurYsWMua7766it17NhR/v7+Cg8PV1JSkrsfDgAAqKTcHjlTpkzRnDlz9NJLL2nnzp2aMmWKkpKS9OKLL1prkpKSNHPmTM2dO1c5OTmqXr26oqOjdfLkSWtNTEyMduzYofT0dK1YsULr16/XoEGDrP1Op1PdunVTgwYNlJubq6lTp2rcuHF65ZVX3P2QAABAJeTj7jv8/PPPdffdd6tHjx6SpIYNG2rx4sXatGmTpN+O4syYMUNjx47V3XffLUl64403FBwcrGXLlqlPnz7auXOn0tLStHnzZrVt21aS9OKLL6p79+6aNm2awsLClJqaqtOnT+v111+Xr6+vmjVrpry8PKWkpLjEEAAA8ExuP5Jz0003KSMjQ7t375Ykffnll9qwYYNuv/12SdLevXuVn5+vqKgo63sCAgLUrl07ZWdnS5Kys7MVGBhoBY4kRUVFydvbWzk5OdaaTp06ydfX11oTHR2tXbt26ejRoxed7dSpU3I6nS43AABgJrcfyRk9erScTqcaN26sKlWq6OzZs/rXv/6lmJgYSVJ+fr4kKTg42OX7goODrX35+fkKCgpyHdTHR7Vr13ZZExERccF9nNtXq1atC2abNGmSxo8f74ZHCQAAKjq3H8l55513lJqaqkWLFmnLli1auHChpk2bpoULF7r7R12yMWPGqKioyLodOHDA7pEAAEAZcfuRnJEjR2r06NHq06ePJKlFixb697//rUmTJql///4KCQmRJBUU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TXl5edatbdu2iomJsf5ctWpVZWRkWN+za9cu7d+/X5GRkZKkyMhIbdu2TYcPH7bWpKeny+FwqGnTptaa8+/j3Jpz9wEAADyb28/JqVmzppo3b+6yrXr16qpTp461PTY2VgkJCapdu7YcDoeGDh2qyMhItW/fXpLUrVs3NW3aVA8//LCSkpKUn5+vsWPHKi4uTn5+fpKkxx9/XC+99JJGjRqlRx55RGvWrNE777yjlStXuvshAQCASqhMTjz+X6ZPny5vb2/17t1bp06dUnR0tGbPnm3tr1KlilasWKHBgwcrMjJS1atXV//+/TVhwgRrTUREhFauXKkRI0bohRdeUP369fXaa68pOjrajocEAAAqmHKJnHXr1rl87e/vr1mzZmnWrFm/+z0NGjTQxx9//If327lzZ23dutUdIwIAAMPw2VUAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACMROQAAwEhEDgAAMBKRAwAAjETkAAAAIxE5AADASEQOAAAwEpEDAACMROQAAAAjETkAAMBIRA4AADASkQMAAIxE5AAAACO5PXImTZqkG264QTVr1lRQUJB69uypXbt2uaw5efKk4uLiVKdOHdWoUUO9e/dWQUGBy5r9+/erR48euuKKKxQUFKSRI0fqzJkzLmvWrVun1q1by8/PT1dffbUWLFjg7ocDAAAqKbdHTmZmpuLi4rRx40alp6eruLhY3bp10/Hjx601I0aM0EcffaSlS5cqMzNThw4dUq9evaz9Z8+eVY8ePXT69Gl9/vnnWrhwoRYsWKDExERrzd69e9WjRw916dJFeXl5Gj58uB599FGtWrXK3Q8JAABUQj7uvsO0tDSXrxcsWKCgoCDl5uaqU6dOKioq0rx587Ro0SLdeuutkqT58+erSZMm2rhxo9q3b6/Vq1fr66+/1qeffqrg4GC1atVKzz33nJ566imNGzdOvr6+mjt3riIiIpScnCxJatKkiTZs2KDp06crOjra3Q8LAABUMmV+Tk5RUZEkqXbt2pKk3NxcFRcXKyoqylrTuHFj/e1vf1N2drYkKTs7Wy1atFBwcLC1Jjo6Wk6nUzt27LDWnH8f59acu4+LOXXqlJxOp8sNAACYqUwjp6SkRMOHD1eHDh3UvHlzSVJ+fr58fX0VGBjosjY4OFj5+fnWmvMD59z+c/v+aI3T6dSvv/560XkmTZqkgIAA6xYeHn7ZjxEAAFRMZRo5cXFx2r59u95+++2y/DF/2pgxY1RUVGTdDhw4YPdIAACgjLj9nJxz4uPjtWLFCq1fv17169e3toeEhOj06dMqLCx0OZpTUFCgkJAQa82mTZtc7u/cu6/OX/Pf78gqKCiQw+FQtWrVLjqTn5+f/Pz8LvuxAQCAis/tR3JKS0sVHx+vDz74QGvWrFFERITL/jZt2qhq1arKyMiwtu3atUv79+9XZGSkJCkyMlLbtm3T4cOHrTXp6elyOBxq2rSpteb8+zi35tx9AAAAz+b2IzlxcXFatGiRPvzwQ9WsWdM6hyYgIEDVqlVTQECAYmNjlZCQoNq1a8vhcGjo0KGKjIxU+/btJUndunVT06ZN9fDDDyspKUn5+fkaO3as4uLirCMxjz/+uF566SWNGjVKjzzyiNasWaN33nlHK1eudPdDAgAAlZDbj+TMmTNHRUVF6ty5s0JDQ63bkiVLrDXTp0/XHXfcod69e6tTp04KCQnR+++/b+2vUqWKVqxYoSpVqigyMlIPPfSQ+vXrpwkTJlhrIiIitHLlSqWnp+u6665TcnKyXnvtNd4+DgAAJJXBkZzS0tL/ucbf31+zZs3SrFmzfndNgwYN9PHHH//h/XTu3Flbt2695BkBAID5+OwqAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABiJyAEAAEYicgAAgJGIHAAAYCQiBwAAGInIAQAARiJyAACAkYgcAABgJCIHAAAYicgBAABGqvSRM2vWLDVs2FD+/v5q166dNm3aZPdIAACgAqjUkbNkyRIlJCTon//8p7Zs2aLrrrtO0dHROnz4sN2jAQAAm1XqyElJSdHAgQM1YMAANW3aVHPnztUVV1yh119/3e7RAACAzXzsHuCvOn36tHJzczVmzBhrm7e3t6KiopSdnX3R7zl16pROnTplfV1UVCRJcjqdZTZnyakTZXbf5aks/47KkwnPB89FxcFzUbGY8HzwXFza/ZeWlv7hukobOT///LPOnj2r4OBgl+3BwcH65ptvLvo9kyZN0vjx4y/YHh4eXiYzmiRght0T4Byei4qD56Ji4fmoOMrrufjll18UEBDwu/srbeT8FWPGjFFCQoL1dUlJiY4cOaI6derIy8vLxsn+OqfTqfDwcB04cEAOh8PucTwaz0XFwvNRcfBcVBymPBelpaX65ZdfFBYW9ofrKm3k1K1bV1WqVFFBQYHL9oKCAoWEhFz0e/z8/OTn5+eyLTAwsKxGLFcOh6NS/wdrEp6LioXno+Lguag4THgu/ugIzjmV9sRjX19ftWnTRhkZGda2kpISZWRkKDIy0sbJAABARVBpj+RIUkJCgvr376+2bdvqxhtv1IwZM3T8+HENGDDA7tEAAIDNKnXkPPDAA/rpp5+UmJio/Px8tWrVSmlpaRecjGwyPz8//fOf/7zgZTiUP56LioXno+Lguag4PO258Cr9X++/AgAAqIQq7Tk5AAAAf4TIAQAARiJyAACAkYgcAABgJCIHAAAYicipZIqLi/XII49o7969do8CAECFRuRUMlWrVtV7771n9xg4z3fffaehQ4cqKipKUVFReuKJJ/Tdd9/ZPRb+y4kTZny6M3CptmzZom3btllff/jhh+rZs6eefvppnT592sbJyh6RUwn17NlTy5Yts3sMSFq1apWaNm2qTZs2qWXLlmrZsqVycnLUrFkzpaen2z2ex+natasOHjx4wfZNmzapVatW5T+QBystLdXSpUs1ZMgQ3XvvverVq5fLDeXnscce0+7duyVJ33//vfr06aMrrrhCS5cu1ahRo2yermxV6isee6pGjRppwoQJysrKUps2bVS9enWX/U888YRNk3me0aNHa8SIEZo8efIF25966in9/e9/t2kyz+Tv76+WLVtq9uzZeuCBB1RSUqIJEybo+eef15AhQ+wez6MMHz5cL7/8srp06aLg4GB5eXnZPZLH2r17txX5S5cuVadOnbRo0SJlZWWpT58+mjFjhq3zlSWueFwJRURE/O4+Ly8vff/99+U4jWfz9/fXtm3b1KhRI5ftu3fvVsuWLXXy5EmbJvNcs2bN0qhRo3T33Xdr3759+ve//6358+erW7dudo/mUWrXrq233npL3bt3t3sUj+dwOJSbm6tGjRrp73//u+644w4NGzZM+/fv17XXXqtff/3V7hHLDEdyKiFOOq446tWrp7y8vAsiJy8vT0FBQTZN5dni4uL0ww8/aMqUKfLx8dG6det000032T2WxwkICNCVV15p9xiQ1LZtW02cOFFRUVHKzMzUnDlzJP32u8T0z3rknBzgMgwcOFCDBg3SlClT9Nlnn+mzzz7T5MmT9dhjj2ngwIF2j+dxjh49qt69e2vOnDl6+eWXdf/996tbt26aPXu23aN5nHHjxmn8+PFGHyWoLGbMmKEtW7YoPj5ezzzzjK6++mpJ0rvvvmv8PwB4uaqSSEhI+NNrU1JSynASnK+0tFQzZsxQcnKyDh06JEkKCwvTyJEj9cQTT3AeQjn7v//7P0VEROjNN9+0XtZdsmSJhgwZovbt22vlypU2T+g5fv31V91zzz3KyspSw4YNVbVqVZf9W7ZssWkynHPy5ElVqVLlgufGJEROJdGlSxeXr7ds2aIzZ87o2muvlfTbOSBVqlRRmzZttGbNGjtG9Hi//PKLJKlmzZo2T+K5nnvuOT3zzDPy9nY9SP3DDz9owIABvOOtHN1///1au3at7r333oueePzPf/7Tpsk8V25urnbu3ClJatq0qVq3bm3zRGWPyKmEUlJStG7dOi1cuFC1atWS9Nth+gEDBqhjx4568sknbZ7Q8/z000/atWuXJKlx48aqW7euzRN5nuLiYjVu3FgrVqxQkyZN7B7H41WvXl2rVq3SzTffbPcoHu/w4cN64IEHlJmZqcDAQElSYWGhunTporffflv16tWzd8AyxDk5lVBycrImTZpkBY4k1apVSxMnTlRycrKNk3me48eP65FHHlFoaKg6deqkTp06KTQ0VLGxsVx8rpxVrVqVd7NVIOHh4XI4HHaPAUlDhw7VsWPHtGPHDh05ckRHjhzR9u3b5XQ6jb/kCJFTCTmdTv30008XbP/pp5+sl0xQPhISEpSZmamPPvpIhYWFKiws1IcffqjMzEyOqNkgLi5OU6ZM0ZkzZ+wexeMlJydr1KhR2rdvn92jeLy0tDTNnj3b5Qhn06ZNNWvWLH3yySc2Tlb2eLmqEurXr58+++wzJScn68Ybb5Qk5eTkaOTIkerYsaMWLlxo84Seo27dunr33XfVuXNnl+1r167V/ffff9EYRdm55557lJGRoRo1aqhFixYXXCjz/ffft2kyz1OrVi2dOHFCZ86c0RVXXHHBya1HjhyxaTLPU7NmTX322WcXXPV769atuuWWW+R0Ou0ZrBxwnZxK4quvvlLz5s3l7e2tuXPn6h//+If69u2r4uJiSZKPj49iY2M1depUmyf1LCdOnLjodSaCgoJ4ucoGgYGB6t2790X38U638mXyVXQrm1tvvVXDhg3T4sWLFRYWJkk6ePCgRowYoa5du9o8XdniSE4lUaVKFf34448KCgrSlVdeqc2bN8vf39/6IMirrrrqgn+1oux17dpVderU0RtvvCF/f39Jv711tn///jpy5Ig+/fRTmyf0LIsXL9aDDz540X0jR47kHwHwSAcOHNBdd92lHTt2KDw83NrWvHlzLV++XPXr17d5wrJD5FQSderU0ccff6x27drJ29tbBQUFRp8RX1ls375d0dHROnXqlK677jpJ0pdffil/f3+tWrVKzZo1s3lCzxIYGKjFixfr9ttvd9mekJCgxYsX68cff7RpMs909uxZLVu2zHrbcrNmzXTXXXepSpUqNk/meUpLS/Xpp5/qm2++kSQ1adJEUVFRNk9V9oicSmLQoEF64403FBoaqv3796t+/fq/+z8KPruqfJ04cUKpqaku//OIiYlRtWrVbJ7M86xcuVIxMTFasWKF9dbloUOH6r333tOaNWvUuHFjmyf0HN9++626d++ugwcPWtfz2rVrl8LDw7Vy5UpdddVVNk8IT0DkVCJpaWn69ttv9cQTT2jChAm/e9G5YcOGlfNkQMWxaNEixcfHKz09XfPmzdOHH36otWvX6pprrrF7NI/SvXt3lZaWKjU1VbVr15Yk/ec//9FDDz0kb29vrj5dzjIyMjR9+nTrqFqTJk00fPhw44/mEDmV0IABAzRz5kyurFtB7NmzR2vXrtXhw4dVUlLisi8xMdGmqTzb7NmzlZCQoHr16mnt2rXWZ/Wg/FSvXl0bN25UixYtXLZ/+eWX6tChg44dO2bTZJ5n9uzZGjZsmO69915FRkZKkjZu3Kh3331X06dPV1xcnM0Tlh0iB7gMr776qgYPHqy6desqJCTE5R08Xl5efD5POfi9z3VbunSpWrdu7fKyCJ/rVn5q166tFStWXPABkFlZWbrzzjt5C3k5ql+/vkaPHq34+HiX7bNmzdLzzz+vgwcP2jRZ2SNygMvQoEEDDRkyRE899ZTdo3is//5ct9/j5eXF57qVo379+mnLli2aN2+ey/W8Bg4cqDZt2mjBggX2DuhBatSooby8vAuOaO7Zs0fXX3+90UfViBzgMjgcDuXl5enKK6+0exSgQiksLFT//v310UcfWRcCPHPmjO666y4tWLBAAQEBNk/oOfr27avrr79eI0eOdNk+bdo0ffHFF3r77bdtmqzsETnAZYiNjdUNN9ygxx9/3O5RgAppz5492rlzp7y8vNSkSRPOjyonM2fOtP7sdDo1bdo0dejQweWcnKysLD355JMaO3asXWOWOSIHuETn/8/j+PHjSklJUY8ePdSiRYsLLl1v+offAX/GuV8zXHW6/ERERPypdV5eXkZfdoTIAS4R//MA/pw33nhDU6dO1Z49eyRJ11xzjUaOHKmHH37Y5sngKfjsKuAS7d271+4RgAovJSVFzz77rOLj49WhQwdJ0oYNG/T444/r559/1ogRI2ye0HOsXbv2T5+gbxqO5AAA3C4iIkLjx49Xv379XLYvXLhQ48aN4x8L5cjPz0/169fXgAED1L9/f+vzqzwBkQNcph9++EHLly/X/v37dfr0aZd9XJcFnsrf31/bt2+/6NuWW7RooZMnT9o0mef5+eef9eabb2rhwoXasWOHbr31VsXGxqpnz57y9fW1e7wyReQAlyEjI0N33XWXrrzySn3zzTdq3ry59u3bp9LSUrVu3ZrrssBjNW/eXH379tXTTz/tsn3ixIlasmSJtm3bZtNknm3Lli2aP3++Fi9eLOm3t5fHxsZaHzBsGiIHuAw33nijbr/9do0fP141a9bUl19+qaCgIMXExOi2227T4MGD7R4RsMV7772nBx54QFFRUdY5OVlZWcrIyNA777yje+65x+YJPdehQ4f0yiuvaPLkyfLx8dHJkycVGRmpuXPnqlmzZnaP51bedg8AVGY7d+60zjnw8fHRr7/+qho1amjChAmaMmWKzdMB9undu7dycnJUt25dLVu2TMuWLVPdunW1adMmAscGxcXFevfdd9W9e3c1aNBAq1at0ksvvaSCggJ9++23atCgge677z67x3Q73l0FXIbq1atb5+GEhobqu+++s/4l9PPPP9s5GmC7Nm3a6K233rJ7DI83dOhQLV68WKWlpXr44YeVlJSk5s2bW/urV6+uadOmKSwszMYpywaRA1yG9u3ba8OGDWrSpIm6d++uJ598Utu2bdP777+v9u3b2z0eYJt+/fqpS5cuuuWWW/jYE5t9/fXXeumll3TPPffIz8/vomvq1q2rtWvXlvNkZY+Xq4DLkJKSonbt2kmSxo8fr65du2rJkiVq2LCh5s2bZ/N0gH18fX01adIkXX311QoPD9dDDz2k1157zbowIMpP165ddeLEiQsC5/XXX7deVvfx8dEtt9xix3hlihOPgcvQv39/xcbGqlOnTnaPAlRIBw8e1Pr165WZmanMzEzt3r1boaGh+uGHH+wezWM0bNhQixYt0k033eSyPScnR3369DH6mkUcyQEuQ1FRkaKiotSoUSM9//zzOnTokN0jARVKrVq1VKdOHdWqVUuBgYHy8fFRvXr17B7Lo+Tn5ys0NPSC7fXq1dOPP/5ow0Tlh8gBLsOyZct08OBBDR48WEuWLFGDBg10++23a+nSpSouLrZ7PMA2Tz/9tG666SbVqVNHo0eP1smTJzV69Gjl5+dr69atdo/nUcLDw5WVlXXB9qysLCNPNj4fL1cBbnTuQluvvfaaatSooYceekhDhgxRo0aN7B4NKFfe3t6qV6+eRowYoV69eumaa66xeySPlZSUpKSkJE2dOlW33nqrpN8uZDpq1Cg9+eSTGjNmjM0Tlh3eXQW4yY8//qj09HSlp6erSpUq6t69u7Zt26amTZsqKSmJDySER9m6dasyMzO1bt06JScny9fXV7fccos6d+6szp07Ez3laOTIkfrPf/6jIUOGWJe88Pf311NPPWV04EgcyQEuS3FxsZYvX6758+dr9erVatmypR599FH17dtXDodDkvTBBx/okUce0dGjR22eFrDPl19+qenTpys1NVUlJSU6e/as3SN5nGPHjmnnzp2qVq2aGjVq9LtvJzcJR3KAyxAaGqqSkhI9+OCD2rRpk1q1anXBmi5duigwMLDcZwPsVFpaqq1bt2rdunVat26dNmzYIKfTqZYtWxr5VuXKoEaNGrrhhhvsHqNccSQHuAxvvvmm7rvvPvn7+9s9ClCh1KpVS8eOHdN1111nvUzVsWNHgh/lisgBALjdypUr1bFjR+tlW8AORA4AADAS5+QAANyiV69eWrBggRwOh3r16vWHa99///1ymgqejMgBALhFQECAvLy8rD//nnNrgLJG5AAA3GL+/PnWn7t166YHH3zwoutGjhxZXiPBw/GxDgAAtxs8eLA++eSTC7YnJCTorbfesmEieCIiBwDgdqmpqXrwwQe1YcMGa9vQoUP19ttva+3atTZOBk/Cu6sAAGVi0aJFio+PV3p6uubNm6cPP/xQa9eu5SMdUG44JwcAUCb69u2rwsJCdejQQfXq1VNmZqauvvpqu8eCB+FIDgDALRISEi66fenSpWrdurWuuuoqa1tKSkp5jQUPRuQAANyiS5cuf2qdl5eX1qxZU8bTAEQOAAAwFO+uAgAARiJyAACAkYgcAABgJCIHAAAYicgBAABGInIAAICRiBwAAGAkIgcAABjp/wGFzeKhyvFsXQAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "result['count'].plot.bar()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "대신증권의 Cybos Plus 가 가장 많은 데이터를 제공하는 것을 확인할 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/source/notebooks_ipynb/koapy-tutorial.ipynb b/docs/source/notebooks_ipynb/koapy-tutorial.ipynb deleted file mode 100644 index 8273200e..00000000 --- a/docs/source/notebooks_ipynb/koapy-tutorial.ipynb +++ /dev/null @@ -1,6641 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 키움증권 OpenAPI+ 사용 예시" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import logging" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "logging.basicConfig(\n", - " format='%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d',\n", - " level=logging.DEBUG)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "logging.getLogger('matplotlib').setLevel(logging.WARNING)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. 엔트리포인트 객체 생성" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "from koapy import KiwoomOpenApiPlusEntrypoint" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:22:15,134 [DEBUG] Testing if client is ready... - KiwoomOpenApiPlusEntrypoint.py:45\n", - "2022-01-18 14:22:25,146 [DEBUG] Client is not ready - KiwoomOpenApiPlusEntrypoint.py:47\n", - "2022-01-18 14:22:25,146 [DEBUG] Creating a new server... - KiwoomOpenApiPlusEntrypoint.py:48\n" - ] - } - ], - "source": [ - "entrypoint = KiwoomOpenApiPlusEntrypoint()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "주요한 기능들은 해당 엔트리포인트의 멤버함수로써 제공된다.\n", - "\n", - "예를 들어 아래와 같이 서버 접속 이전에도 실행 가능한 아래 함수를 활용하면 OpenAPI 가 정상적으로 로드되었는지 간접적으로 확인 가능하다." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "module_path = entrypoint.GetAPIModulePath()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'C:\\\\OpenAPI'" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "module_path" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. 서버 접속" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "entrypoint.EnsureConnected()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "자동 로그인 설정이 되어있는 경우 로그인이 자동으로 처리되며, 그렇지 않은 경우에는 수동으로 아이디, 비밀번호 등 로그인 정보를 입력해 처리해주어야 한다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "만약에 함수 인자로 `credentials` 정보를 주는 경우 [`pywinauto`](https://github.com/pywinauto/pywinauto) 를 활용하여 자동으로 로그인 처리를 진행한다.\n", - "앞서 언급한 키움증권에서 기본으로 제공하는 자동 로그인이 아니라 기존에 수동으로 처리하던 과정을 매크로 형태로 자동으로 처리하는 방식이다.\n", - "참고로 [`pywinauto`](https://github.com/pywinauto/pywinauto) 사용을 위해서는 **관리자 권한**이 필요하다." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "credentials = {\n", - " 'user_id': 'id',\n", - " 'user_password': 'password',\n", - " 'cert_password': 'password',\n", - " 'is_simulation': True,\n", - " 'account_passwords': {\n", - " '0000000000': '0000',\n", - " } \n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "entrypoint.EnsureConnected(credentials)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "참고로 여기서는 이미 로그인이 되어있는 상황이므로 위의 함수가 추가적인 로그인처리를 진행하지는 않게 된다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. 기본 함수 실행" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다시 한번 기본 함수를 통해 접속상태를 확인해보자. 아래 값이 1 인 경우 정상 접속 상태이다. 접속되어 있지 않은 경우라면 0 을 반환한다." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "entrypoint.GetConnectState()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이후 예시들에서 사용하기 위해 삼성전자의 코드를 확인한다." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "codes = entrypoint.GetCodeListByMarketAsList('0')\n", - "names = [entrypoint.GetMasterCodeName(code) for code in codes]" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "codes_by_name = dict(zip(names, codes))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위에서 `GetCodeListByMarketAsList()` 함수는 기존의 `GetCodeListByMarket()` 함수 호출시 나오는 문자열 형태의 결과를 편의를 위해 리스트 형태로 변환해서 제공한다." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "code = samsung_code = codes_by_name['삼성전자']" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'005930'" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. TR 요청 예시" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 상위 함수 사용 예시" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "몇가지 자주 쓰이는 TR 들에 대해서는 요청 및 결과 이벤트 처리까지 완료해서 결과물만 반환하는 상위함수를 제공하고 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "info = entrypoint.GetStockBasicInfoAsDict(code) # opt10001" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'종목코드': '005930',\n", - " '종목명': '삼성전자',\n", - " '결산월': '12',\n", - " '액면가': '100',\n", - " '자본금': '7780',\n", - " '상장주식': '5969783',\n", - " '신용비율': '+0.13',\n", - " '연중최고': '+79800',\n", - " '연중최저': '-76400',\n", - " '시가총액': '4596733',\n", - " '시가총액비중': '',\n", - " '외인소진률': '+52.23',\n", - " '대용가': '60450',\n", - " 'PER': '20.05',\n", - " 'EPS': '3841',\n", - " 'ROE': '10.0',\n", - " 'PBR': '1.95',\n", - " 'EV': '5.36',\n", - " 'BPS': '39406',\n", - " '매출액': '2368070',\n", - " '영업이익': '359939',\n", - " '당기순이익': '264078',\n", - " '250최고': '+91800',\n", - " '250최저': '-68300',\n", - " '시가': '+77600',\n", - " '고가': '+77800',\n", - " '저가': '-76600',\n", - " '상한가': '+100500',\n", - " '하한가': '-54300',\n", - " '기준가': '77500',\n", - " '예상체결가': '-0',\n", - " '예상체결수량': '0',\n", - " '250최고가일': '20210115',\n", - " '250최고가대비율': '-16.12',\n", - " '250최저가일': '20211013',\n", - " '250최저가대비율': '+12.74',\n", - " '현재가': '-77000',\n", - " '대비기호': '5',\n", - " '전일대비': '-500',\n", - " '등락율': '-0.65',\n", - " '거래량': '7715780',\n", - " '거래대비': '-87.83',\n", - " '액면가단위': '원',\n", - " '유통주식': '4456888',\n", - " '유통비율': '74.7'}" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "info" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:22:38,267 [DEBUG] Received 600 records from 2022-01-18 00:00:00 to 2019-08-16 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:38,572 [DEBUG] Received 600 records from 2019-08-14 00:00:00 to 2017-03-03 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:38,880 [DEBUG] Received 600 records from 2017-03-02 00:00:00 to 2014-09-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:39,197 [DEBUG] Received 600 records from 2014-09-25 00:00:00 to 2012-04-20 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:56,202 [DEBUG] Received 600 records from 2012-04-19 00:00:00 to 2009-11-24 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:56,502 [DEBUG] Received 600 records from 2009-11-23 00:00:00 to 2007-06-27 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:56,797 [DEBUG] Received 600 records from 2007-06-26 00:00:00 to 2005-01-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:57,109 [DEBUG] Received 600 records from 2005-01-25 00:00:00 to 2002-08-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:22:57,409 [DEBUG] Received 600 records from 2002-08-23 00:00:00 to 2000-03-08 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:14,210 [DEBUG] Received 600 records from 2000-03-07 00:00:00 to 1997-12-09 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:14,499 [DEBUG] Received 600 records from 1997-12-08 00:00:00 to 1995-11-22 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:14,780 [DEBUG] Received 600 records from 1995-11-21 00:00:00 to 1993-11-10 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:15,089 [DEBUG] Received 600 records from 1993-11-09 00:00:00 to 1991-10-28 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:15,396 [DEBUG] Received 600 records from 1991-10-26 00:00:00 to 1989-10-06 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:32,236 [DEBUG] Received 600 records from 1989-10-05 00:00:00 to 1987-09-09 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:32,523 [DEBUG] Received 600 records from 1987-09-08 00:00:00 to 1985-08-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:32,641 [DEBUG] Received 192 records from 1985-08-24 00:00:00 to 1985-01-04 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n" - ] - } - ], - "source": [ - "data = entrypoint.GetDailyStockDataAsDataFrame(code) # opt10081" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드현재가거래량거래대금일자시가고가저가수정주가구분수정비율대업종구분소업종구분종목정보수정주가이벤트전일종가
000593077000771578059586120220118776007780076600
177500878512267890320220117776007780076900
2773001009672578157520220114777007810077100
37790013889401108859820220113793007930077900
4789001100050286891120220112795007960078600
................................................
978780104970119850109824082407950
9788830012930419850108840084008300
9789841011810319850107840085008390
979083901660019850105840084408390
979184501710019850104850085008450
\n", - "

9792 rows × 15 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 현재가 거래량 거래대금 일자 시가 고가 저가 수정주가구분 \\\n", - "0 005930 77000 7715780 595861 20220118 77600 77800 76600 \n", - "1 77500 8785122 678903 20220117 77600 77800 76900 \n", - "2 77300 10096725 781575 20220114 77700 78100 77100 \n", - "3 77900 13889401 1088598 20220113 79300 79300 77900 \n", - "4 78900 11000502 868911 20220112 79500 79600 78600 \n", - "... ... ... ... ... ... ... ... ... ... \n", - "9787 8010 4970 1 19850109 8240 8240 7950 \n", - "9788 8300 12930 4 19850108 8400 8400 8300 \n", - "9789 8410 11810 3 19850107 8400 8500 8390 \n", - "9790 8390 1660 0 19850105 8400 8440 8390 \n", - "9791 8450 1710 0 19850104 8500 8500 8450 \n", - "\n", - " 수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가 \n", - "0 \n", - "1 \n", - "2 \n", - "3 \n", - "4 \n", - "... ... ... ... ... ... ... \n", - "9787 \n", - "9788 \n", - "9789 \n", - "9790 \n", - "9791 \n", - "\n", - "[9792 rows x 15 columns]" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "데이터가 최대한 있는 그대로 (주로 문자열 형태로) 반환되기 때문에 필요하다면 타입 변환을 거쳐 사용한다." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "dates = pd.to_datetime(data['일자'], format='%Y%m%d')\n", - "closes = pd.to_numeric(data['현재가'])" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(dates, closes)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "주가 데이터에서 수정주가가 필요한 경우에는 `adjusted_price=True` 파라미터를 설정해 호출한다." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:23:33,209 [DEBUG] Received 600 records from 2022-01-18 00:00:00 to 2019-08-16 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:33,499 [DEBUG] Received 600 records from 2019-08-14 00:00:00 to 2017-03-03 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:50,269 [DEBUG] Received 600 records from 2017-03-02 00:00:00 to 2014-09-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:50,553 [DEBUG] Received 600 records from 2014-09-25 00:00:00 to 2012-04-20 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:50,856 [DEBUG] Received 600 records from 2012-04-19 00:00:00 to 2009-11-24 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:51,210 [DEBUG] Received 600 records from 2009-11-23 00:00:00 to 2007-06-27 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:23:51,505 [DEBUG] Received 600 records from 2007-06-26 00:00:00 to 2005-01-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:08,257 [DEBUG] Received 600 records from 2005-01-25 00:00:00 to 2002-08-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:08,558 [DEBUG] Received 600 records from 2002-08-23 00:00:00 to 2000-03-08 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:08,848 [DEBUG] Received 600 records from 2000-03-07 00:00:00 to 1997-12-09 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:09,238 [DEBUG] Received 600 records from 1997-12-08 00:00:00 to 1995-11-22 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:09,534 [DEBUG] Received 600 records from 1995-11-21 00:00:00 to 1993-11-10 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:26,266 [DEBUG] Received 600 records from 1993-11-09 00:00:00 to 1991-10-28 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:26,564 [DEBUG] Received 600 records from 1991-10-26 00:00:00 to 1989-10-06 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:26,885 [DEBUG] Received 600 records from 1989-10-05 00:00:00 to 1987-09-09 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:27,240 [DEBUG] Received 600 records from 1987-09-08 00:00:00 to 1985-08-26 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n", - "2022-01-18 14:24:27,345 [DEBUG] Received 192 records from 1985-08-24 00:00:00 to 1985-01-04 00:00:00 for code 005930 - KiwoomOpenApiPlusServiceClientStubWrapper.py:573\n" - ] - } - ], - "source": [ - "data_adjusted = entrypoint.GetDailyStockDataAsDataFrame(code, adjusted_price=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "dates = pd.to_datetime(data_adjusted['일자'], format='%Y%m%d')\n", - "closes = pd.to_numeric(data_adjusted['현재가'])" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYQAAAD4CAYAAADsKpHdAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAr5ElEQVR4nO3deXxU1f3/8dcnOxDCvglIUBDEXXBBrRuiqG21Li21VVu1VH9+v1+t/bU/bK1dFLXWVutXa0u1brV1rztuuCsKAZEdAUEEooQ9ELJM5vz+uHcmM5mZZJJMZibk/Xw88si5555775lwmc+95557jjnnEBERycl0BUREJDsoIIiICKCAICIiPgUEEREBFBBERMSXl+kKtFbfvn1daWlppqshItKhzJ07d5Nzrl+8dR02IJSWllJWVpbpaoiIdChm9nmidWoyEhERQAFBRER8CggiIgIoIIiIiE8BQUREAAUEERHxKSCIiAiggCAikjU27azh5UXlGTu+AoKISJa45IE5XP7PeWzfXZeR4ysgiIhkic83VwEQDGZm4jIFBBGRLBGawdIsM8dXQBARyRI7qgMAvLbkq4wcXwFBRCTLPDbni4wcVwFBRCTL5ORkps1IAUFEJMvkZughggKCiEiWcaiXkYiIABnqdaqAICKSdRQQREQEYEn5Dh6dvTbtx1VAEBHJMjtrAkx9emHaj6uAICIigAKCiEjW6NOtIKPHV0AQEckSx4zoG7UcGtsoXRQQRESyROPX0eat3ZrW4ysgiIhkicb3A+feMyutx1dAEBHJEs9/siEm75IH5nD3myvTcnwFBBGRLPbGso384ZXlaTmWAoKIiAAKCCIiWeOkUf0yevykAoKZ/cTMFpvZIjP7t5kVmVlvM3vNzFb4v3tFlL/WzFaa2XIzOy0if6yZLfTX3WnmjfFqZoVm9pif/5GZlab8k4qIZLlApka18zUbEMxsMPA/wDjn3IFALjAZmArMdM6NBGb6y5jZGH/9AcAk4C9mluvv7h5gCjDS/5nk518KbHXOjQBuB36fkk8nItKBBOod+/TtlnD9Bys38dTcde12/GSbjPKALmaWB3QFNgBnAQ/66x8EzvbTZwGPOudqnHOrgZXAkWY2CChxzs1y3tsWDzXaJrSvJ4EJobsHEZHOIugc/boXsuaWM+Ouv+Dej/jpE5+02/GbDQjOufXAbcBaoBzY7px7FRjgnCv3y5QD/f1NBgORE4Ku8/MG++nG+VHbOOcCwHagT+O6mNkUMyszs7KKiopkP6OISIcQdI6cDF4LJ9Nk1AvvCn44sBfQzcy+39QmcfJcE/lNbROd4dx059w459y4fv0y+/BFRCTVgg5yMzSfMiTXZHQKsNo5V+GcqwOeBo4BvvKbgfB/b/TLrwOGRmw/BK+JaZ2fbpwftY3fLNUD2NKaDyQi0lHVBx3J3CC8uXxj84VaIZmAsBY42sy6+u36E4ClwHPAxX6Zi4Fn/fRzwGS/59BwvIfHs/1mpUozO9rfz0WNtgnt6zzgDZfuUZ1ERDLMORe+QygpyktY7rn5sW80p0LiI/qccx+Z2ZPAPCAAfAxMB4qBx83sUrygcb5ffrGZPQ4s8ctf6Zyr93d3BfAA0AWY4f8A3Ac8bGYr8e4MJqfk04mIdCD1Ec8QZv/yFJyD0//8Dms2V/Hq4i/D5fLaqVmp2YAA4Jz7NfDrRtk1eHcL8cpPA6bFyS8DDoyTX40fUEREOqtgkHBAKMr3euuPGtidNZurmPLw3HC59npfQW8qi4hkCa+XUXTex2u3xZRTQBAR2cPF63a6sbImpty5hw+OyUsFBQQRkSyRTLfTX39jDCeO6t9kmdZSQBARyRLBJLqdFuS139e2AoKISJYIRnQ7TeTTLyvb7fgKCCIiWaI+iaErKqsD7XZ8BQQRkSzxxZbdzTYZ5eW239AWCggiIlkgNJ/y0/PWR+UX5Ud/Tbfn4HcKCCIiWWD26vjDt+U2CgDtORiqAoKISBZYu6Uqbn5dGmdRU0AQEckC9Qm++P912VFpq4MCgohIFnD+FDCNB64bV9qb3511QHg5UeBIBQUEEZEsMGH0AAB+d1bM+J9R7ybUBILtVgcFBBGRLLB3764AHDi4JGZdfk7DV/XlJ+zbbnVQQBARyQL1/pxg8bqVVuxsGOBuqB842oMCgohIFgg9G4j34tnWXbXhdHtNjgMKCCIiWSEUEBq/dwCQGxEkQhPntAcFBBGRLBAMNRnFuQOor/fWXXv66HatgwKCiEgWaOoO4QD/QfP+g2IfOKdSUnMqi4hI+3pmvjeWUbyhKc4+dDAHDe7JiP7F7VoH3SGIiGSBdz6tAKCuPvbFMzNr92AACggiIlnFufSNXdSYAoKISBYJpHEwu8YUEEREssg+/bpl7NgKCCIiWaQwr/3eM2iOAoKIiAAKCCIi4lNAEBERQC+miYhkhV5d8+lakNmvZAUEEZEsMKCkKDwnQqaoyUhEJAsEgi7u0NfppIAgIpImu2vrWbNpV9x19UFHXk5mv5IVEERE0uSKR+Zy4m1vEYzzNnIgGGzXyW+SoYAgIpImby33BrC74cUlMesC9Y5cBQQRkc7l/vfXRC2vqthJTSBIXm4HaDIys55m9qSZLTOzpWY23sx6m9lrZrbC/90rovy1ZrbSzJab2WkR+WPNbKG/7k4zb+RvMys0s8f8/I/MrDTln1REJAut21rFhD++zZZdtWzYtjujdUk2HP0ZeNk5Nxo4BFgKTAVmOudGAjP9ZcxsDDAZOACYBPzFzEKDc9wDTAFG+j+T/PxLga3OuRHA7cDv2/i5REQ6hE07a8Ppt/05ETKl2YBgZiXA8cB9AM65WufcNuAs4EG/2IPA2X76LOBR51yNc241sBI40swGASXOuVnOG/D7oUbbhPb1JDAhdPcgIiLpkcwdwj5ABXC/mX1sZveaWTdggHOuHMD/3d8vPxj4ImL7dX7eYD/dOD9qG+dcANgO9GlcETObYmZlZlZWUZHZSCoikgqRz5Ez/Ew5qYCQBxwO3OOcOwzYhd88lEC8j+SayG9qm+gM56Y758Y558b169ev6VqLiGS5jTuq+eZd74eX9xvQPYO1SS4grAPWOec+8pefxAsQX/nNQPi/N0aUHxqx/RBgg58/JE5+1DZmlgf0ALa09MOIiHQkry75Kmo50y3lzQYE59yXwBdmNsrPmgAsAZ4DLvbzLgae9dPPAZP9nkPD8R4ez/ablSrN7Gj/+cBFjbYJ7es84A2XyYlFRUTSoPF7B5l+cJrs4Hb/DTxiZgXAZ8AP8YLJ42Z2KbAWOB/AObfYzB7HCxoB4ErnXL2/nyuAB4AuwAz/B7wH1g+b2Uq8O4PJbfxcIiJZrTYQjJk/OdNdaZIKCM65+cC4OKsmJCg/DZgWJ78MODBOfjV+QBERyTaTp89i885aXrvmhJTtsz7o2FUTiMrLyXBE0PDXIiLN+PCztj/SXLu5KmrZ4ehaED1/ckfoZSQiIhB3ULpkPfzhmqjl+qBjWJ9u4eW9e3fl5nMObvX+U0EBQUQkSY/O+aL5Qgk0Hqeoui7IjIXl4eWHLz2SMXuVtHr/qaCAICKSpGlxRilNVuOhrY+Y9npUgMnP8MB2oIAgItKk3bX14fTPThvVRMmm9exa0OR6BQQRkSwX2fY/oKSo1fsZ1KPpbTP9QBkUEEREmhT5imx9G96X/WTdtqjlgkZ3BJmeCwEUEEREmnT765+G0/Wt7GXknONvb38GwFUTRgLQvaih1//9PziCHl3y21DL1FBAEBFpQnVdMJwOBYSrHv2Yi/4xO+luqJFjFuXnem1DdfUN+z1pdP+YbTJBAUFEJEmhgPDs/A2882kFd76xIqnttlU1TIITeni8ozqQqHjGKCCIiCTpZ08uYNH67eHl5z/Z0ETpBpE3EtnwrCCR7K2ZiEgW+vr/vhdOr6rYldQ2kc8eCnKzoDtRAgoIIiJx1ATqOebmmSnZ13XPLAqns+F9g0Syt2YiIhm0YVs1G7ZXp3y/XRoNaPedcUMTlEw/BQQRkTiWbNgRTp80KnVT9hbmRQcEFztbcMYoIIiIxNGrW8N7AW8ur0jZfgvyop8hlPbtlqBk+ikgiIjEUVefmiv3peU7opYbz5v84+P3TclxUkEBQUQkjtpAw4tj3ztq77hl9unX/NX90/PWhdMvX/21mFnRGs+rnEkKCCIicby86MtwOlHPoJ5d8pn4p7f546vLE+7n0KG9wunRA0uiAk22UUAQEYnjqYgr+/xcY/IRsb2B5q3dxoqNO/nfN1Ym3E9BXsf5mu04NRURyZDy7dXccm7T01tu3lnD9t11lE59kT+99inl23fz+eZdvBQxKxpAZAPRHd85NPWVbYO85ouIiHQuf3kr+op/RkTzUSJLyyupCXiT6dw5cwV3zowe5+i28w+J2ebswwa3oZappzsEEZFGbn05+plAMsNeOxxf7ahJuP7YEX0AyMnib90srpqISHbJjxiH6JChPaPWBR1c/+wiEhnUowsARvb0KmpMAUFEpBl//f5YAPIiLu931UQPX10XCBJI4k7CsjceKCCIiDRn0oEDgegv84uPKY0qc9lDZUntK/Ri2iFDeqSkbqmkh8oiIknqkp9LVW09T14+nq4Frfv6DMWU7kWZnzKzMd0hiIgk8JNT9osa2O7RKUdz9SkjGTusF2P2KuGKE1s+7EToTeVsGtQuRHcIIiKNDOpRxHEj+nLVKSOj8kcO6M7VA7qHl8cN69V402aFmp2CWfjCsu4QREQaqQ0Ek3rD+OTR/bnh7ANbtO9QQMjGOwQFBBGRCLWBILtqA0kFBDPjwqOHxeTffM5BCbcJNRll4x2CmoxERCLsd90MACqrA82UTOy9FZuilv924dhwul/3wqjf2UR3CCIicTw5d13zhRKIfNi8+LencdoBA8PL+/Yr5q/fH8tN30p8F5EpukMQEYmjKL/118uR8yZ3K4z9mg2915Btkv7EZpZrZh+b2Qv+cm8ze83MVvi/e0WUvdbMVprZcjM7LSJ/rJkt9Nfdaf4bGmZWaGaP+fkfmVlpCj+jiEiL7RfRm6glTtl/ACX+OwbfPTJ2yOxs1pIQeBWwNGJ5KjDTOTcSmOkvY2ZjgMnAAcAk4C9mFgqX9wBTgJH+zyQ//1Jgq3NuBHA78PtWfRoRkRQJuuR7AUU+IyjKz6Ff90Je+8nx/PabLeuBlGlJBQQzGwKcCdwbkX0W8KCffhA4OyL/UedcjXNuNbASONLMBgElzrlZzjkHPNRom9C+ngQmWOOJR0VE2tmHn20Op48s7ZP0dpHPCArzvOvfkQO6d6jJcSD5O4Q7gJ8DkR2lBjjnygH83/39/MHAFxHl1vl5g/104/yobZxzAWA7EPOvYWZTzKzMzMoqKiqSrLqISPOCQcfk6R8CcODgEq49Y3SLtj9hP++N5sI2PHvItGZrbmZfBzY65+Ymuc94V/auifymtonOcG66c26cc25cv3794mwiItI6tfUN17tnHzo44TzKiYQmxylo4XbZJJmaHwt808zWAI8CJ5vZP4Gv/GYg/N8b/fLrgMgnKUOADX7+kDj5UduYWR7QA9jSis8jItIqs1Y1NBfV1bf8LeIPP/O+sl5b8lXK6pRuzQYE59y1zrkhzrlSvIfFbzjnvg88B1zsF7sYeNZPPwdM9nsODcd7eDzbb1aqNLOj/ecDFzXaJrSv8/xjZN973SKyx7rvvdXhdGu6nI7oXwzA+m27U1andGvLvc0twEQzWwFM9Jdxzi0GHgeWAC8DVzrn6v1trsB7ML0SWAXM8PPvA/qY2UrgGvweSyIi6RJq8gE4cnjvFm9/5+TDAOjVNfuGtU5Wi15Mc869BbzlpzcDExKUmwZMi5NfBsT0w3LOVQPnt6QuIiKpVBNoeIZwwF4tn7ymVzcvEBy+d8tHQM0WelNZRASoqfMCwtdG9m3V9oN6dOG+i8cxrrTldxfZQgFBRISGYanPOGhQq/cxYf8BKapNZnTc/lEiIim07MtKoG0BoaNTQBCRTm/Npl3hdF5O5x0kQQFBRDq9rVW14XS80Uk7CwUEEen0Qu8gdI0YtrozUkAQkU5t9uotvLCgHIAfHFOa2cpkmAKCiHRa97+/mm//bVZ4+byxQ5oovedTQBCRTuu3zy+JWi7KV5ORiIgAXRQQREQEOncPI1BAEJEs4Jyjuq6++YLtLD+3876DAAoIIpIFpr/zGaN/9TIzFpazeWdNWo4Zb4T9zj5zb+e+PxKRrHDzjGUAXPHIvHDe3y8ax8Qx7Tc20Kadtc0X6mR0hyAiWelHD5W16/5vnrE0arlnB57HIFUUEEQkqz07fz2lU1+MGm8okYXrtlM69UU+WLWp2bKV1YFwum9xAfOvP7VN9dwTKCCISEY1N1vuVY/OB+DE294K55Wt2cInX2yLKXvZQ3MAuODvHzV73L7FBeF0YV7n7m4aomcIIpJRkTOVRfrmIXvFza8POs77q/d28Zpbzoxa99WO5B9I/3v2F+H0GQcNTHq7PZkCgohk1EsLy2Py9u7dldwcY0ajdbWBICs2Via13/qgIzfBUNa7ahqaiz65/lSKi/RVCGoyEpE0O/+vH4RHFwV4cUH0l/6aW84kP9eorQ9G9ToC+GpHNTe+0PAweMO23eH0xh3VUWXXb91NIk/PWxdO9+ianzBwdDYKCCKSVnPWbOWGF7wxhIJBF/fqfFXFrphAAfD55ipmfbY5vHzMLW8QDHrPII68aWZU2cfK1gJQE6hn6lMLWB8RPHbVZv4luGykgCAiaRP68gaoqg1w7dMLeXb+hnBe724F8Tbjmon7ATBnzZbYfSZ4y/nuN1cB8NqSr3h0zhfc9sry8Lpc/wW0o4b3bsWn2HMpIIhI2jwzf304Peb6V3isrOHB7uvXnMA7Pz8p7nbH79cPgD/PXBGzrt45Dv7NqwmPGXpe8J+PG44dCjw3n3NQC2q/51NAEJG0uebxTxKu69OtgOI4g8udsn9/ujfx0Leqpp7a+oaeSrN/OSGc/sMry2IGrHt41hpuf/1TAAo7+eimjSkgiEhWSDTS6P6DSmICQv/uheH04g07Gq0rCqfvfnNV1DsGlzwwh189u5h1/gPnPD1MjqKAICIZN3HMAAry4n8drd60i5Ki6GEl7vn+2HB6w/aGh8XXnbl/zPaRQ2C8sWxj1LrCBMfsrPTXEJG0iHygHOnMgwfx94vGReVFPlw+ap8+MTOZ7aoJcO7h3nSXP39yQTj/e0cNAyDZC/+eXeM/xO6sFBBEJC1Wb44/FlG87qW/OKPhSv98f57jqaePBuD7R+/NsSP6Mu1bB8Zs16XACxwrp50Rs+6QIT2iln/19TFJ1rzzUEAQkbT48cNzky77rcMGM7hnF6ChWefHx+/DqpvO4MazDyI3x5qc/zgnx5h0QMNwFIcO7UlJl4Zmp4vHD+PS44a39CPs8fS+toikxcqNO+PmD+pRFJOXm2O8P/XkqDwzoyUTmv3XySN4efGXAMz/YhtHRrxz8C2/uUmi6Q5BRDLq7Z/Ff/cgGd87au9weu51p0StK8qP/nqbvbrhpbZDh/Zs9TH3ZAoIIpJWn954ejh93Zn7J+xdlIxLIpp9Gu9nd238UVQlMQUEEWl3j3z0eThdkJcTfgGtX8T7BK2xb7/icLrxAHX5edHL0y/0uqre+d3D2nTMPZkCgoi0q5pAPb/8z6KovIvGe91De3RJ3bSVORYdAEYPLAmn/3XZUZx6wEDW3HJmwnkWRAFBRNrZZQ/Gzo189Sn78ZfvHc4J/hhFbRF6H6GpXkfHjOjb5uN0Bs0GBDMbamZvmtlSM1tsZlf5+b3N7DUzW+H/7hWxzbVmttLMlpvZaRH5Y81sob/uTjMvpJtZoZk95ud/ZGal7fBZRSQDvthSFU6HHuYW5OVwxkGDMGv70BF//PYhMTOnhbxy9fE8cfn4Nh+js0jmDiEA/NQ5tz9wNHClmY0BpgIznXMjgZn+Mv66ycABwCTgL2YWCt33AFOAkf7PJD//UmCrc24EcDvw+xR8NhFJk7r6IP+evZb6OG8jnziqfzj962+k92WwUQO7c0SphrhOVrMBwTlX7pyb56crgaXAYOAs4EG/2IPA2X76LOBR51yNc241sBI40swGASXOuVnOm1X7oUbbhPb1JDDBUnHpICJpccaf3+Xapxfy2JwvYtY98MGacFrdPbNbi54h+E05hwEfAQOcc+XgBQ0gdBkwGIg8K9b5eYP9dOP8qG2ccwFgO9AnzvGnmFmZmZVVVFS0pOoi0o5W+C+d3f3myqh879rPs+R3p6WkiUjaT9IBwcyKgaeAq51zO5oqGifPNZHf1DbRGc5Nd86Nc86N69ev7Q+jRCS11m/bzY0vLKE24L0DUFFZE15XkKs+LNkuqX8hM8vHCwaPOOee9rO/8puB8H+HxpVdBwyN2HwIsMHPHxInP2obM8sDegCxc+WJSNZ5aNaaqOV731vN9+79EIAtVbXhfE1kn/2S6WVkwH3AUufcnyJWPQdc7KcvBp6NyJ/s9xwajvfweLbfrFRpZkf7+7yo0TahfZ0HvOEi7zVFJGv966O1MXlz1mzlqbnrmOMPF3HzOQepuagDSGZwu2OBC4GFZjbfz/sFcAvwuJldCqwFzgdwzi02s8eBJXg9lK50zoVmwL4CeADoAszwf8ALOA+b2Uq8O4PJbftYItIe5qzZwj59u9GnuOEN4y27auOW/ekTDdNl7tO3W7vXTdqu2YDgnHuP+G38ABPiZTrnpgHT4uSXATGDmDvnqvEDiohkn1cXf8naLVXc+OJSgKh+/yVd8tlYWUP3ojwqqwNxt48caVSyl57yiEhcu2vrmbHQm7xmysNzw8EAoHTqi5ROfZGdNYHwsNZl153CxDED+M64oTH7UnNRx6D5EEQkrv2vfxmAK0/aN2GZ2as3h9OFebn8/aJxbNi2m8fKYt9HkOynOwQRadLdb65KuO6SB7xxiiJvAHp2Td2AdZJeCggincisVZu55vH5NNeJr6o2/rOARCJ317UgjxXTTk9cWLKWAoJIlquorOG///0xO6rr2ryv7/79Q56et56l5ZVNlvt8c1WT6xv7r5NGRC3n6yW0Dkn/aiJZ7pYZy3j+kw08PXdd84WTdPbd7ze5/pIH5sTN/58JI7n5nIN4+NIjWXbDJEr7dAVocsL6f//o6NZXVNJKD5VFstxT87xAcNOMZRTk5XJBxDzC8eysCfDByk2cesDAhGVq65ueXrJ8e3XU8nEj+vLPy46KKfdWEvMhj983ZlgyyVIKCCIdRG0gyC/+s5DjRvSlqi7ApDve5exD9+LC8aWMHRaejoSpTy3ghQXlvH7NCYzo3zDF5MuLylt8zIW/OZXuRXpI3FkoIIikSfn23XQtyGvRtJHLvowdR/L4P7wZTj8zfwPPzN8Q9aLYCwu8L/4HPljNjWcfFM6//J/zkjpmZcSzirYEg9m/mNDsnYhkFz1DEEmT8Te/wSG/fTWpsvVBx7qtVUy6492kyl/w9w9j8l5f4o03+elXlXy5vZrRA7tHrY+cySxk2otL+PWzi5M6ZnP6lxQxpFfXlOxL0kN3CCJpEO/LtylTn1rAEy14iPzBqs2UTn0RgDGDSlhSvoMvd1RTUVnDqbe/E1X2kmOH84/3V/O1W9+MurOoqw/y93dXh5fHRTRDSeegOwSRNHj70+QndKqqDcQEgyW/O41p3zqQ0w9seFB8zcT9+Nlpo2K2X1Le0Mx0xLTXY9YfunfPcHrNpl3h9IX3fRRVbsrx+yRdZ9kzKCCItLO/vr2K655ZBHiTyzdnzPWvRC0/c+WxdC3I43tHDWNnTcMLY/8zYSRXnjSCe753eKvrduJtb/Hyoi+prqvnw8+ipyA5fj9NQtXZKCCItLNbZiwLp2sDQYKNJqJ3znHlv+Zx33ur2V1b33hz9u7d0A7/f070XgB74IdHhPNOP2gQT14+nm8cslc477bzD0lYnxNGRn/RX/7PuRz3+zdjyhXl5ybch+yZrKPOQzNu3DhXVlaW6WqINGlXTYADfh19xX/iqH488MMjCQYdOTnG259WcPE/ZgNQXJjHzpoARw7vzU3fOpABJUUt6umzqmIn97y1ipvPOYiRv5wRte7mcw7iO+OGkpNjLFq/na//73tx93Hdmftz0uj+7NuvOO566djMbK5zbly8dbpDEGkn76/cFP6ij/TW8gpeWLCBfX7xEi8uKI8qE2oS2rdfMSP6d29xt899+xVz2/mHkJ+bw9LfTQLg3MOHcOt5B4eDAcCogd3pkuAO4LKv7aNg0EnpDkGkHdz00lKmv/NZePnRKUfz4AdrmLHoy6S2n3XtyQzq0aW9qhcW6pkUKbLnkex5dIcg0kbBoGPWqs3NjhIK3uxikcEAYGBJEReNL024Td/iAroXer3AF/7m1LQEg3juvqD1D6il49N7CCJJuPe9z7jppWXcd/E4Juw/IGG5yuo6pjw8NyZ/795dKW1iXuEfHjucS48bzpZdtRkbKuLei8ZxypjEn032fLpDkD2ec95bv7WBIK8v+Yp1W1v2khjATS95PYVWVewM523dVctvn18c1TPosTnRM4V9/KuJrLnlzHDbfdl1p4TXzbr25HD6ypNGUJSfy149M3NnUHbdKQoGojsE2fM9NW89//eJT6LyWtJOXhNo+MK/6aVljB3Wi7HDenPYDa8BsP/AEr59hDeP8K2vLI/atvHsYX2LC1n4m1MBb5ygD6aeHDOyaDot+u1p5OWYupgKoIAgncBdb6xo0/ajrns5avnce2ZFLf/8qQXhgFAb8AZzW33zGQRd/MnlI5uE9urZJWN3BeB1cxUJUZOR7PE2bIu9An/+kw1JbXviH2Jf2IpnxsLyqB47ZkZuTmwwEMlmCgiyx6qorKF06otxh2D+739/nNQ+1kRMJfnPS2MniAm54pGGoaWnXzi2BbUUyR4KCLLHijewW0vMXt0wts+/LjuK40b25YnLx3Po0J7h/NevOT5mu5NH92/TcUUyRQFB9jjvrqjg47Vb4647PGKkz+ZMfWpBOH3MiL4AHFHam2euPJZbzz2YASWFDOsT3ZX0/aknk6cJ5qWD0hMl2aM457jwvtjhIsAbQrprQR6XPDCHN5ZtxDnHwvXbWfHVTnbVBrj+2cX0LS6g7LqJANT4D4gvGj8sZl/fPmIo548bgpmx9HeTCDpHNz2glQ5OZ7DsUeY1ujMYWFLErecdzH4DutO1wDvd31jmzST21vIKfvjAnKjym3bW8uTcdRw7og/rt+0G4HdnHRj3WKEeRF0K1GVT9gwKCLJHadwl9IOpJ4dfCmuscTAIafzOgkhnocZO2WO8tuSrqOX9BhTHDQazfzEh6X3+sYl5BUT2NLpDkJSrqg3gHGlvU3/ko8/D6ZXTTicnzkth4E3+HumxKUdz5PDemBm3vryMv7y1KrzunMMHt09lRbKQAoK0yLsrKrhlxjKmnj6arzWaeWv+F9u4640VvL7Ua6MfM6iExy8fz7aqWtZuqeKYffu2W71mrdrMW8u9eYvn/Wpi0j195v1qIr27FYSXfz5pND87bRTXPP4Jpx84MO6bxiJ7Ks2HIEmrrK7joN+8Gl4+Zf/+bKuqo+zz+F08G3vl6uMZNbB7i455+A2vsWVXLW//7MSYLp4vLSzn/0S8EBai8fxFEmtqPgTdIUhCzjm2VtXxWcVOzvvrrJj1oTuBxp66Yjy3v7aC91Zuiso/7Y53ACgpyiMvN4f7f3AEpX26saR8B3e9uYL3V24Ol73w6GFc4g8HDXDCH95iyvH7cNH4YQzu2YW73ljJH1/7NObYo1sYcESkQdbcIZjZJODPQC5wr3PulqbK72l3CDWBet5YupH9BnZnYEkROWaYgXNQmJeTsKdMe9heVcePHi6LelM3ZNywXjx5xTHMWFgeHq7h/00azYCSQiaOGRAzln91XT2ffLGN70z/sN3qO2F0f+6YfChLNuxgXGlvjSEk0oSm7hCyIiCYWS7wKTARWAfMAb7rnFuSaJv2DAi1gSDrt+1ma1Ut26pq2bqrjsrqOuqd98W9Y3eAzzfvYsO23RQX5VEfdBhG7+ICigvy6F9SSF29oz4Y9H87AsEgwSAs2rCdbVV19O1eyMYd1RhQ0iWfZV9WNlmn/t0L6d2tgO5FeVTXBTGDIb28UTLr6h3bqmrZvKuWYNAxtHdXCvNy2b67lqG9u1JSlE9xYR676+rZVRNgY2UNzjnq6h0lXfJY/mUlldUB6oMOB+Gr8pDD9u7Jn79zGH27F4T78rdU6Dz7ZN12Jk+fxcGDezJ7TUPA+fmkUZx2wED27t2V91Zu4of3N3QJnX/9RG6ZsYxHG801sN+AYl79yQmtqo9IZ9URAsJ44DfOudP85WsBnHM3J9qmtQHhXx+t5Z63VxIMQn3QEXTej5eG3XX11NUHae7Psk/fbvQpLqA+6DWrgBdINu+qoSYQJD8nh9wcIy/XyMsxcnNyyDFvEvVA0DFuWK/wNImbd9VQUpTP4F5dGNm/mHVbd1Pt12PH7gBln29h9KASXlxQzvC+3ejfvZAN23cTDHovReXlGN2L8ujf3es9s25rFZ9t2kVhXi4FuUZlTYBdNQG65OfSrTCPHdV1DO7ZheLCPLZU1TJqQHf6FhfiPT81uhXkcuDgHnzjkL3a9Wq7sroOM4s7BPPyLyt5d0UFZx48KPx3WrR+OyVF+Ty/YAPFhXlcfExpu9VNZE/VEZ4hDAYiL//WATFDS5rZFGAKwN57792qAw3sUcgRw3qTk2PkGOTmGDn+UMU5ZhTm5VCYn8uw3l3pXVxAr64F9OqaT0lRPjk5Rn6uUZSXm7AJxznXbj1T7r6gXXabMU1NFTlqYPeYB9AHDu4BeLOLiUjqZUtAiPcNGnON7pybDkwH7w6hNQc6efQATh7dflMFqpuiiHRU2fKm8jpgaMTyECC5GUxERCQlsiUgzAFGmtlwMysAJgPPZbhOIiKdSlY0GTnnAmb2X8AreN1O/+GcW5zhaomIdCpZERAAnHMvAS9luh4iIp1VtjQZiYhIhikgiIgIoIAgIiI+BQQREQGyZOiK1jCzCuDzBKv7ApsSrEsX1SE76pDp46sOqkO21WGYc65fvBUdNiA0xczKEo3VoTp0rjpk+viqg+qQjXVIRE1GIiICKCCIiIhvTw0I0zNdAVSHkEzXIdPHB9UhRHXwZEMd4tojnyGIiEjL7al3CCIi0kIKCCIiAnSQgGBm/zCzjWa2KCLvEDObZWYLzex5Myvx8/PN7EE/f2loOs5G+3sucl/prIOZfdfPX2BmL5tZ33aqQ4GZ3e/nf2JmJ/r5Xc3sRTNbZmaLzeyWdvw7xK1DxLrpZvapX5dzkzz+UDN70/+7Ljazq/z83mb2mpmt8H/3itjmWjNbaWbLzey0iPyxft1WmtmdluTsRqmsQ8T6Fp2TKf47tOqcbGkdzKyPX36nmd0VsZ9Wn5OpqoO/Li3npJlNNLO5/t98rpmdHLGvVp2TKeOcy/of4HjgcGBRRN4c4AQ/fQlwg5++AHjUT3cF1gClEdudA/wrcl/pqgPe6LIbgb7+ulvx5pJujzpcCdzvp/sDc/EuALoCJ/n5BcC7wOnprIO//FvgRj+dE/qbJHH8QcDhfro78Ckwxv9bTvXzpwK/99NjgE+AQmA4sArI9dfNBsbjzdg3I9m/Qyrr0NpzMlV1aMs52Yo6dAOOAy4H7orYT6vPyVTVIc3n5GHAXn76QGB9xL5adU6m6idtB2pzRb0v1MgvoR00PBQfCizx098FnvdP9D7+P05vf10x8J7/j9WigJCKOgD5QAUwzP8H/yswpZ3qcDfw/YhyM4Ej4+zvz8CP0l0HvDm0u6XgvHgWmAgsBwb5eYOA5X76WuDaiPKv+P/hBgHLIvK/C/wtnXVIxTmZgr9Dm8/JZOsQUe4HNPoybus5mYo6pOucbFTWgM14gTpl52RrfzpEk1ECi4Bv+unzaZiC80lgF1AOrAVuc85t8dfdAPwRqMpEHZxzdcAVwEK8KULHAPe1Ux0+Ac4yszwzGw6MJXqaUsysJ/ANvC/qtNXBPy7ADWY2z8yeMLMWT3RtZqV4V1sfAQOcc+UA/u/+frHBeP/RQ9b5eYP9dOP8dNYBUnBOtqUOqTonk6xDMvvpSSvPybbUIc3nZKRzgY+dczWk6Jxsi44cEC4BrjSzuXi3abV+/pFAPbAX3q3xT81sHzM7FBjhnPtPBuuQj/ef7zB/3QK8K7f2qMM/8E6oMuAO4AMgENrIzPKAfwN3Ouc+S3Md8vDmzX7fOXc4MAu4rSUHNLNi4CngaufcjqaKxslzTeSnrQ6pOCdTUIc2n5MtqENz+2n1OZmCOqTznAyVPwD4PfDjUFacYml9LyBrZkxrKefcMuBUADPbDzjTX3UB8LJ/5bPRzN4HxuE13Yw1szV4n7u/mb3lnDsxzXXAObfK3+ZxvLbFVktUB+dcAPhJqJyZfQCsiNh0OrDCOXdHW47fyjpsxrsiDn0RPgFcmuzx/C+xp4BHnHNP+9lfmdkg51y5mQ3CaxcHLyBF3hkNwbsSXuenG+ensw7jacM5maI6HAqtPydbWIfmtOqcTFEd0nlOYmZD/GNdFPrb08ZzMhU67B2CmfX3f+cA1+G1fYLXRHOyeboBR+O1y93jnNvLOVeK91Dp07YEg9bUAVgPjDGz0EiDE4Gl7VEH83pudPPTE4GAc26Jv3wj0AO4ui3Hbm0dnNdA+jxwor+LCcCSJI9leE0aS51zf4pY9RxwsZ++GK8dN5Q/2cwK/WarkcBs/xa+0syO9vd5UcQ26apDq8/JVNWBNpyTrahDU/tq1TmZqjqk85z0m6dexHum835EHVp9TqZMOh9YtPYH7zayHKjDi6KXAlfhPaz9FLiFhoeaxXjRfTHeP+jP4uyvlJb3MkpJHfB6NyzFuzV/HujTTnUoxXuotRR4HW/IW/CuOpyfP9//uSyddfDXDQPe8f8OM4G9kzz+cX79F0TU/wy8u6+ZeHcgM/E7Evjb/BKvV81yInpt4N21LfLX3RWqdzrr0NpzMsV/h1adk62swxpgC7DTP3/GtOWcTFUd0nlO4l007YooOx/o35ZzMlU/GrpCRESADtxkJCIiqaWAICIigAKCiIj4FBBERARQQBAREZ8CgoiIAAoIIiLi+/9Josr5NxvNeQAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(dates, closes)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 하위 함수 사용 예시" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "만약에 필요한 TR 에 대한 편의함수가 제공되지 않는 경우라면 아래처럼 직접 TR 요청에 필요한 입력값을 설정해 요청하고, 이후 스트림 형태로 들어오는 이벤트 또한 직접 처리해주는 방식으로 사용할 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "rqname = '주식기본정보요청'\n", - "trcode = 'opt10001'\n", - "screen_no = '0001' # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당\n", - "inputs = {'종목코드': code}" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "output = {}" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:24:27,606 [INFO] Requesting data for request name: 주식기본정보요청 - :1\n", - "2022-01-18 14:24:44,007 [INFO] Got event for request: 주식기본정보요청 - :3\n" - ] - } - ], - "source": [ - "logging.info('Requesting data for request name: %s', rqname)\n", - "for event in entrypoint.TransactionCall(rqname, trcode, screen_no, inputs):\n", - " logging.info('Got event for request: %s', rqname)\n", - " names = event.single_data.names\n", - " values = event.single_data.values\n", - " for name, value in zip(names, values):\n", - " output[name] = value" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'종목코드': '005930',\n", - " '종목명': '삼성전자',\n", - " '결산월': '12',\n", - " '액면가': '100',\n", - " '자본금': '7780',\n", - " '상장주식': '5969783',\n", - " '신용비율': '+0.13',\n", - " '연중최고': '+79800',\n", - " '연중최저': '-76400',\n", - " '시가총액': '4596733',\n", - " '시가총액비중': '',\n", - " '외인소진률': '+52.23',\n", - " '대용가': '60450',\n", - " 'PER': '20.05',\n", - " 'EPS': '3841',\n", - " 'ROE': '10.0',\n", - " 'PBR': '1.95',\n", - " 'EV': '5.36',\n", - " 'BPS': '39406',\n", - " '매출액': '2368070',\n", - " '영업이익': '359939',\n", - " '당기순이익': '264078',\n", - " '250최고': '+91800',\n", - " '250최저': '-68300',\n", - " '시가': '+77600',\n", - " '고가': '+77800',\n", - " '저가': '-76600',\n", - " '상한가': '+100500',\n", - " '하한가': '-54300',\n", - " '기준가': '77500',\n", - " '예상체결가': '-0',\n", - " '예상체결수량': '0',\n", - " '250최고가일': '20210115',\n", - " '250최고가대비율': '-16.12',\n", - " '250최저가일': '20211013',\n", - " '250최저가대비율': '+12.74',\n", - " '현재가': '-77000',\n", - " '대비기호': '5',\n", - " '전일대비': '-500',\n", - " '등락율': '-0.65',\n", - " '거래량': '7726846',\n", - " '거래대비': '-87.95',\n", - " '액면가단위': '원',\n", - " '유통주식': '4456888',\n", - " '유통비율': '74.7'}" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "output" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위의 코드에서 `TransactionCall()` 함수의 경우 반환되는 스트림의 `event` 객체는 `ListenResponse` 타입의 gRPC 메시지 형태로 반환된다." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "from pprint import PrettyPrinter\n", - "from google.protobuf.json_format import MessageToDict\n", - "\n", - "pp = PrettyPrinter()\n", - "\n", - "def pprint_event(event):\n", - " pp.pprint(MessageToDict(event, preserving_proto_field_name=True))" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'arguments': [{'string_value': '0001'},\n", - " {'string_value': '주식기본정보요청'},\n", - " {'string_value': 'opt10001'},\n", - " {'string_value': ''},\n", - " {'string_value': '0'}],\n", - " 'name': 'OnReceiveTrData',\n", - " 'single_data': {'names': ['종목코드',\n", - " '종목명',\n", - " '결산월',\n", - " '액면가',\n", - " '자본금',\n", - " '상장주식',\n", - " '신용비율',\n", - " '연중최고',\n", - " '연중최저',\n", - " '시가총액',\n", - " '시가총액비중',\n", - " '외인소진률',\n", - " '대용가',\n", - " 'PER',\n", - " 'EPS',\n", - " 'ROE',\n", - " 'PBR',\n", - " 'EV',\n", - " 'BPS',\n", - " '매출액',\n", - " '영업이익',\n", - " '당기순이익',\n", - " '250최고',\n", - " '250최저',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '상한가',\n", - " '하한가',\n", - " '기준가',\n", - " '예상체결가',\n", - " '예상체결수량',\n", - " '250최고가일',\n", - " '250최고가대비율',\n", - " '250최저가일',\n", - " '250최저가대비율',\n", - " '현재가',\n", - " '대비기호',\n", - " '전일대비',\n", - " '등락율',\n", - " '거래량',\n", - " '거래대비',\n", - " '액면가단위',\n", - " '유통주식',\n", - " '유통비율'],\n", - " 'values': ['005930',\n", - " '삼성전자',\n", - " '12',\n", - " '100',\n", - " '7780',\n", - " '5969783',\n", - " '+0.13',\n", - " '+79800',\n", - " '-76400',\n", - " '4596733',\n", - " '',\n", - " '+52.23',\n", - " '60450',\n", - " '20.05',\n", - " '3841',\n", - " '10.0',\n", - " '1.95',\n", - " '5.36',\n", - " '39406',\n", - " '2368070',\n", - " '359939',\n", - " '264078',\n", - " '+91800',\n", - " '-68300',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '+100500',\n", - " '-54300',\n", - " '77500',\n", - " '-0',\n", - " '0',\n", - " '20210115',\n", - " '-16.12',\n", - " '20211013',\n", - " '+12.74',\n", - " '-77000',\n", - " '5',\n", - " '-500',\n", - " '-0.65',\n", - " '7726846',\n", - " '-87.95',\n", - " '원',\n", - " '4456888',\n", - " '74.7']}}\n" - ] - } - ], - "source": [ - "pprint_event(event)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "해당 메시지의 형태는 [`koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto`](https://github.com/elbakramer/koapy/blob/master/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto) 파일의 내용, 구체적으로 아래와 같은 메시지의 정의 부분을 참고하기 바란다.\n", - "\n", - "```proto\n", - "message ListenResponse {\n", - " string name = 1;\n", - " repeated Argument arguments = 2;\n", - " SingleData single_data = 3;\n", - " MultiData multi_data = 4;\n", - "}\n", - "```\n", - "\n", - "각 TR 에 따라 싱글데이터/멀티데이터가 선택적으로 설정되어 반환되는데, 그러한 입력/출력과 관련된 정보들은 [KOAStudio](https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf#page=7) 프로그램을 활용하거나 아니면 아래처럼 `KiwoomOpenApiPlusTrInfo` 를 통해 프로그램 내에서 확인할 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "from koapy import KiwoomOpenApiPlusTrInfo" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code('opt10001')" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 6, 9001)]" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tr_info.inputs" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 389),\n", - " KiwoomOpenApiPlusTrInfo.Field('종목명', 20, 50, 302),\n", - " KiwoomOpenApiPlusTrInfo.Field('결산월', 40, 20, 315),\n", - " KiwoomOpenApiPlusTrInfo.Field('액면가', 60, 20, 310),\n", - " KiwoomOpenApiPlusTrInfo.Field('자본금', 80, 20, 309),\n", - " KiwoomOpenApiPlusTrInfo.Field('상장주식', 100, 20, 312),\n", - " KiwoomOpenApiPlusTrInfo.Field('신용비율', 120, 20, 329),\n", - " KiwoomOpenApiPlusTrInfo.Field('연중최고', 140, 20, 1006),\n", - " KiwoomOpenApiPlusTrInfo.Field('연중최저', 160, 20, 1009),\n", - " KiwoomOpenApiPlusTrInfo.Field('시가총액', 180, 20, 311),\n", - " KiwoomOpenApiPlusTrInfo.Field('시가총액비중', 200, 20, 336),\n", - " KiwoomOpenApiPlusTrInfo.Field('외인소진률', 220, 20, 314),\n", - " KiwoomOpenApiPlusTrInfo.Field('대용가', 240, 20, 308),\n", - " KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600),\n", - " KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604),\n", - " KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630),\n", - " KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601),\n", - " KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608),\n", - " KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605),\n", - " KiwoomOpenApiPlusTrInfo.Field('매출액', 380, 20, 1610),\n", - " KiwoomOpenApiPlusTrInfo.Field('영업이익', 400, 20, 1611),\n", - " KiwoomOpenApiPlusTrInfo.Field('당기순이익', 420, 20, 1614),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최고', 440, 20, 1000),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최저', 460, 20, 1003),\n", - " KiwoomOpenApiPlusTrInfo.Field('시가', 480, 20, 16),\n", - " KiwoomOpenApiPlusTrInfo.Field('고가', 500, 20, 17),\n", - " KiwoomOpenApiPlusTrInfo.Field('저가', 520, 20, 18),\n", - " KiwoomOpenApiPlusTrInfo.Field('상한가', 540, 20, 305),\n", - " KiwoomOpenApiPlusTrInfo.Field('하한가', 560, 20, 306),\n", - " KiwoomOpenApiPlusTrInfo.Field('기준가', 580, 20, 307),\n", - " KiwoomOpenApiPlusTrInfo.Field('예상체결가', 600, 20, 10023),\n", - " KiwoomOpenApiPlusTrInfo.Field('예상체결수량', 620, 20, 10024),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최고가일', 640, 20, 1001),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최고가대비율', 660, 20, 1002),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최저가일', 680, 20, 1004),\n", - " KiwoomOpenApiPlusTrInfo.Field('250최저가대비율', 700, 20, 1005),\n", - " KiwoomOpenApiPlusTrInfo.Field('현재가', 720, 20, 10),\n", - " KiwoomOpenApiPlusTrInfo.Field('대비기호', 740, 20, 25),\n", - " KiwoomOpenApiPlusTrInfo.Field('전일대비', 760, 20, 11),\n", - " KiwoomOpenApiPlusTrInfo.Field('등락율', 780, 20, 12),\n", - " KiwoomOpenApiPlusTrInfo.Field('거래량', 800, 20, 13),\n", - " KiwoomOpenApiPlusTrInfo.Field('거래대비', 820, 20, 30),\n", - " KiwoomOpenApiPlusTrInfo.Field('액면가단위', 840, 20, 796),\n", - " KiwoomOpenApiPlusTrInfo.Field('유통주식', 840, 20, 1683),\n", - " KiwoomOpenApiPlusTrInfo.Field('유통비율', 840, 20, 1684)]" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tr_info.single_outputs" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tr_info.multi_outputs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5. 조건검색 예시" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "조건검색을 사용하기 위해서는 먼저 서버에 저장된 조건들을 불러와야 한다." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "entrypoint.EnsureConditionLoaded()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "불러온 조건들의 목록은 아래 함수로 확인이 가능하다." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "conditions = entrypoint.GetConditionNameListAsList()" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[(0, '대형 저평가 우량주'), (1, '중소형 저평가주')]" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "conditions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이후 예시의 정상동작을 위해서는 아래에서 사용되는 조건들과 같은 이름을 가지는 조건들이 미리 저장되어 있어야 한다.\n", - "\n", - "- 대형 저평가 우량주\n", - "- 중소형 저평가주\n", - "\n", - "위의 조건식들은 키움에서 예시로 제공하는 추천식들을 그대로 이름을 똑같이 해서 저장한 것들이다.\n", - "참고로 조건들을 편집하고 저장하는건 영웅문 HTS 내부에서만 가능하기 때문에 따로 HTS 를 열어 편집해주어야 한다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "조건식이 편집된 이후에 해당 조건식을 기존에 동작중인 OpenAPI 에도 갱신하고 싶은 경우, 아래 함수를 통해 편집된 조건식을 새로 불러온다." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "entrypoint.LoadCondition()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 일반 조건검색 예시" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [], - "source": [ - "condition_name = '대형 저평가 우량주'" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [], - "source": [ - "codes, info = entrypoint.GetCodeListByCondition(condition_name, with_info=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위의 함수에서 `with_info=True` 로 호출하게 되면 조건을 만족하는 코드 목록 (`codes`) 뿐만 아니라 해당 종목들에 대한 기본정보들도 (`info`) 같이 가져와 DataFrame 형태로 제공한다." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드종목명현재가기준가전일대비전일대비기호등락율거래량거래대금체결량...ELW만기일미결제약정미결제전일대비이론가내재변동성델타감마쎄타베가로
0000240한국앤컴퍼니-1415014450-3005-2.0856285805+3...00000000
1001800오리온홀딩스-1490015000-1005-0.6752845787+9...00000000
2001880DL건설-2795029500-15505-5.25933022648+84...00000000
3003230삼양식품-9140093800-24005-2.56381493516+4...00000000
4003550LG-7930080500-12005-1.4918069214450+14...00000000
5004000롯데정밀화학-7160072500-9005-1.24569624103+1...00000000
6006040동원산업-219000222500-35005-1.572350520-1...00000000
7006390한일현대시멘트-3185033050-12005-3.6324037775-1...00000000
8006650대한유화-175000179000-40005-2.23350236159+1...00000000
9007310오뚜기-438000438500-5005-0.111551681-1...00000000
10007700F&F홀딩스-2945030150-7005-2.32462781390+28...00000000
11009970영원무역홀딩스+4955049400+1502+0.3011145554+1...00000000
12011780금호석유-162500167500-50005-2.9911604619104-1...00000000
13014830유니드-9630099500-32005-3.22601415907+14...00000000
14017960한국카본-1140011850-4505-3.806134687088-7...00000000
15020000한섬-3560036350-7505-2.06735512649-1...00000000
16021240코웨이+7400073100+9002+1.23809765959-1...00000000
17025540한국단자+7380073300+5002+0.6810834796+2...00000000
18030520한글과컴퓨터-2240022900-5005-2.182154904889-60...00000000
19033290코웰패션-82608370-1105-1.312914282448+1267...00000000
20033780KT&G-7840078900-5005-0.6317582813818+1000...00000000
21036830솔브레인홀딩스-3150032400-9005-2.78469801504+50...00000000
22042420네오위즈홀딩스+7270070700+20002+2.8336009726578-1...00000000
23049070인탑스+3515033250+19002+5.7137040612957+227...00000000
24056190에스에프에이-3460035100-5005-1.42853822968+35...00000000
25057050현대홈쇼핑-6210062500-4005-0.645482342-1...00000000
26060150인선이엔티-1120011550-3505-3.032543582890-1...00000000
27064960SNT모티브-4455045900-13505-2.94341471537+9...00000000
28069080웹젠-2460025000-4005-1.601425983564-1...00000000
29081660휠라홀딩스-3080031600-8005-2.532406107499+2...00000000
30095660네오위즈+3255031200+13502+4.3364296420979-4...00000000
31096530씨젠-5400054100-1005-0.1850025227426-25...00000000
32110790크리스에프앤씨-4375044250-5005-1.1313699604-1...00000000
33111770영원무역+4790047250+6502+1.381401266809-2...00000000
34137310에스디바이오센서+5180049750+20502+4.1246072523807-30...00000000
35161390한국타이어앤테크놀로지-3560037300-17005-4.5633936412253+2...00000000
36161890한국콜마-3710037800-7005-1.85531041995-1...00000000
37185750종근당-9630098600-23005-2.33280452749+70...00000000
38192080더블유게임즈-5310053600-5005-0.93444882377+1...00000000
39192400쿠쿠홀딩스1845018450030.0014766273+1...00000000
40200130콜마비앤에이치-2865029100-4505-1.55439361271+1...00000000
41271560오리온-101500103500-20005-1.93840318592-26...00000000
42284740쿠쿠홈시스3750037500030.0022255836-1...00000000
43285130SK케미칼-140000142000-20005-1.41416345872-1...00000000
44294870HDC현대산업개발-1635018750-24005-12.805960884101615+13...00000000
45300720한일시멘트-1905020900-18505-8.8583026416299-100...00000000
46950130엑세스바이오-1590016600-7005-4.222662934292+1...00000000
\n", - "

47 rows × 63 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 종목명 현재가 기준가 전일대비 전일대비기호 등락율 거래량 \\\n", - "0 000240 한국앤컴퍼니 -14150 14450 -300 5 -2.08 56285 \n", - "1 001800 오리온홀딩스 -14900 15000 -100 5 -0.67 52845 \n", - "2 001880 DL건설 -27950 29500 -1550 5 -5.25 93302 \n", - "3 003230 삼양식품 -91400 93800 -2400 5 -2.56 38149 \n", - "4 003550 LG -79300 80500 -1200 5 -1.49 180692 \n", - "5 004000 롯데정밀화학 -71600 72500 -900 5 -1.24 56962 \n", - "6 006040 동원산업 -219000 222500 -3500 5 -1.57 2350 \n", - "7 006390 한일현대시멘트 -31850 33050 -1200 5 -3.63 24037 \n", - "8 006650 대한유화 -175000 179000 -4000 5 -2.23 35023 \n", - "9 007310 오뚜기 -438000 438500 -500 5 -0.11 1551 \n", - "10 007700 F&F홀딩스 -29450 30150 -700 5 -2.32 46278 \n", - "11 009970 영원무역홀딩스 +49550 49400 +150 2 +0.30 11145 \n", - "12 011780 금호석유 -162500 167500 -5000 5 -2.99 116046 \n", - "13 014830 유니드 -96300 99500 -3200 5 -3.22 60141 \n", - "14 017960 한국카본 -11400 11850 -450 5 -3.80 613468 \n", - "15 020000 한섬 -35600 36350 -750 5 -2.06 73551 \n", - "16 021240 코웨이 +74000 73100 +900 2 +1.23 80976 \n", - "17 025540 한국단자 +73800 73300 +500 2 +0.68 10834 \n", - "18 030520 한글과컴퓨터 -22400 22900 -500 5 -2.18 215490 \n", - "19 033290 코웰패션 -8260 8370 -110 5 -1.31 291428 \n", - "20 033780 KT&G -78400 78900 -500 5 -0.63 175828 \n", - "21 036830 솔브레인홀딩스 -31500 32400 -900 5 -2.78 46980 \n", - "22 042420 네오위즈홀딩스 +72700 70700 +2000 2 +2.83 360097 \n", - "23 049070 인탑스 +35150 33250 +1900 2 +5.71 370406 \n", - "24 056190 에스에프에이 -34600 35100 -500 5 -1.42 85382 \n", - "25 057050 현대홈쇼핑 -62100 62500 -400 5 -0.64 5482 \n", - "26 060150 인선이엔티 -11200 11550 -350 5 -3.03 254358 \n", - "27 064960 SNT모티브 -44550 45900 -1350 5 -2.94 34147 \n", - "28 069080 웹젠 -24600 25000 -400 5 -1.60 142598 \n", - "29 081660 휠라홀딩스 -30800 31600 -800 5 -2.53 240610 \n", - "30 095660 네오위즈 +32550 31200 +1350 2 +4.33 642964 \n", - "31 096530 씨젠 -54000 54100 -100 5 -0.18 500252 \n", - "32 110790 크리스에프앤씨 -43750 44250 -500 5 -1.13 13699 \n", - "33 111770 영원무역 +47900 47250 +650 2 +1.38 140126 \n", - "34 137310 에스디바이오센서 +51800 49750 +2050 2 +4.12 460725 \n", - "35 161390 한국타이어앤테크놀로지 -35600 37300 -1700 5 -4.56 339364 \n", - "36 161890 한국콜마 -37100 37800 -700 5 -1.85 53104 \n", - "37 185750 종근당 -96300 98600 -2300 5 -2.33 28045 \n", - "38 192080 더블유게임즈 -53100 53600 -500 5 -0.93 44488 \n", - "39 192400 쿠쿠홀딩스 18450 18450 0 3 0.00 14766 \n", - "40 200130 콜마비앤에이치 -28650 29100 -450 5 -1.55 43936 \n", - "41 271560 오리온 -101500 103500 -2000 5 -1.93 84031 \n", - "42 284740 쿠쿠홈시스 37500 37500 0 3 0.00 22255 \n", - "43 285130 SK케미칼 -140000 142000 -2000 5 -1.41 41634 \n", - "44 294870 HDC현대산업개발 -16350 18750 -2400 5 -12.80 5960884 \n", - "45 300720 한일시멘트 -19050 20900 -1850 5 -8.85 830264 \n", - "46 950130 엑세스바이오 -15900 16600 -700 5 -4.22 266293 \n", - "\n", - " 거래대금 체결량 ... ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가 로 \n", - "0 805 +3 ... 00000000 \n", - "1 787 +9 ... 00000000 \n", - "2 2648 +84 ... 00000000 \n", - "3 3516 +4 ... 00000000 \n", - "4 14450 +14 ... 00000000 \n", - "5 4103 +1 ... 00000000 \n", - "6 520 -1 ... 00000000 \n", - "7 775 -1 ... 00000000 \n", - "8 6159 +1 ... 00000000 \n", - "9 681 -1 ... 00000000 \n", - "10 1390 +28 ... 00000000 \n", - "11 554 +1 ... 00000000 \n", - "12 19104 -1 ... 00000000 \n", - "13 5907 +14 ... 00000000 \n", - "14 7088 -7 ... 00000000 \n", - "15 2649 -1 ... 00000000 \n", - "16 5959 -1 ... 00000000 \n", - "17 796 +2 ... 00000000 \n", - "18 4889 -60 ... 00000000 \n", - "19 2448 +1267 ... 00000000 \n", - "20 13818 +1000 ... 00000000 \n", - "21 1504 +50 ... 00000000 \n", - "22 26578 -1 ... 00000000 \n", - "23 12957 +227 ... 00000000 \n", - "24 2968 +35 ... 00000000 \n", - "25 342 -1 ... 00000000 \n", - "26 2890 -1 ... 00000000 \n", - "27 1537 +9 ... 00000000 \n", - "28 3564 -1 ... 00000000 \n", - "29 7499 +2 ... 00000000 \n", - "30 20979 -4 ... 00000000 \n", - "31 27426 -25 ... 00000000 \n", - "32 604 -1 ... 00000000 \n", - "33 6809 -2 ... 00000000 \n", - "34 23807 -30 ... 00000000 \n", - "35 12253 +2 ... 00000000 \n", - "36 1995 -1 ... 00000000 \n", - "37 2749 +70 ... 00000000 \n", - "38 2377 +1 ... 00000000 \n", - "39 273 +1 ... 00000000 \n", - "40 1271 +1 ... 00000000 \n", - "41 8592 -26 ... 00000000 \n", - "42 836 -1 ... 00000000 \n", - "43 5872 -1 ... 00000000 \n", - "44 101615 +13 ... 00000000 \n", - "45 16299 -100 ... 00000000 \n", - "46 4292 +1 ... 00000000 \n", - "\n", - "[47 rows x 63 columns]" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "info" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 실시간 조건검색 예시\n", - "\n", - "같은 조건식은 1분에 1건 제한이므로 예시 실행시 제한을 회피하기 위해서 새로 설정한다." - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "condition_name = '중소형 저평가주'" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:28:20,494 [INFO] Start listening realtime condition stream... - :1\n" - ] - } - ], - "source": [ - "logging.info('Start listening realtime condition stream...')\n", - "stream = entrypoint.GetCodeListByConditionAsStream(condition_name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "실시간 조건검색의 경우 조건에 만족/불만족하는 종목이 편입/이탈할때마다 계속해서 이벤트를 반환한다. 예시에서는 10초 동안만 이벤트를 확인해본다." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "import threading\n", - "\n", - "def stop_listening():\n", - " logging.info('Stop listening realtime condition events...')\n", - " stream.cancel()\n", - " \n", - "threading.Timer(65.0, stop_listening).start() # 65초 이후에 gRPC 커넥션 종료하도록 설정" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'arguments': [{'string_value': '8686'},\n", - " {'string_value': '900290;900310;900340;002170;017890;036190;037710;049430;073560;084650;140910;187870;192440;210540;225220;352700;950190;900280;900250;'},\n", - " {'string_value': '중소형 저평가주'},\n", - " {'long_value': '1'},\n", - " {'long_value': '0'}],\n", - " 'name': 'OnReceiveTrCondition'}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:25,810 [INFO] Stop listening realtime condition events... - :4\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "<_MultiThreadedRendezvous of RPC that terminated with:\n", - "\tstatus = StatusCode.CANCELLED\n", - "\tdetails = \"Locally cancelled by application!\"\n", - "\tdebug_error_string = \"None\"\n", - ">\n" - ] - } - ], - "source": [ - "import grpc\n", - "\n", - "events = []\n", - "\n", - "try:\n", - " for event in stream:\n", - " events.append(event)\n", - " pprint_event(event)\n", - "except grpc.RpcError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위에서 `stream` 결과는 [`grpc`](https://grpc.github.io/grpc/python/) 의 [`_MultiThreadedRendezvous`](https://github.com/grpc/grpc/blob/53ba4a101e80e1a67d4ec741b7e1aad6ea8d790f/src/python/grpcio/grpc/_channel.py#L652) 객체인데 사실 해당 타입은 직접적으로 외부에 노출되는 타입은 아니다. 대신에 해당 타입은 내부적으로 [`grpc.RpcError`](https://grpc.github.io/grpc/python/grpc.html?highlight=rpcerror#grpc.RpcError), [`grpc.RpcContext`](https://grpc.github.io/grpc/python/grpc.html?highlight=rpccontext#grpc.RpcContext), [`grpc.Call`](https://grpc.github.io/grpc/python/grpc.html?highlight=call#grpc.Call), [`grpc.Future`](https://grpc.github.io/grpc/python/grpc.html?highlight=future#grpc.Future) 인터페이스를 구현하고 있으므로 해당 객체의 사용법과 관련해서는 각각의 인터페이스를 참고하자." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "최초 이벤트로 반환되는 코드 목록들에 대해서 앞선 일반조건 검색 예시에서와 같이 종목들의 기본정보들을 별도로 가져오고 싶다면 대략 아래처럼 해볼 수 있다." - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [], - "source": [ - "if len(events) > 0:\n", - " codes = events[0].arguments[1].string_value.strip(';').split(';')\n", - "else:\n", - " codes = [samsung_code]" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['900290',\n", - " '900310',\n", - " '900340',\n", - " '002170',\n", - " '017890',\n", - " '036190',\n", - " '037710',\n", - " '049430',\n", - " '073560',\n", - " '084650',\n", - " '140910',\n", - " '187870',\n", - " '192440',\n", - " '210540',\n", - " '225220',\n", - " '352700',\n", - " '950190',\n", - " '900280',\n", - " '900250']" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "codes" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [], - "source": [ - "info = entrypoint.GetStockQuoteInfoAsDataFrame(codes)" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드종목명현재가기준가전일대비전일대비기호등락율거래량거래대금체결량...ELW만기일미결제약정미결제전일대비이론가내재변동성델타감마쎄타베가로
0900290GRT12251225030.00123651152-130...00000000
1900310컬러레이-14251465-405-2.73147191213+294...00000000
2900340윙입푸드-11751215-405-3.29187400224-144...00000000
3002170삼양통상-5750057900-4005-0.693467201-4...00000000
4017890한국알콜-1150011600-1005-0.8656037647+1...00000000
5036190금화피에스시-3045030800-3505-1.143356102+1...00000000
6037710광주신세계171500171500030.0051088-28...00000000
7049430코메론-1045010600-1505-1.4220522215+2...00000000
8073560우리손에프앤지-21352150-155-0.70162170349-170...00000000
9084650랩지노믹스-2290023000-1005-0.431389753241+1...00000000
10140910에이리츠+79307900+302+0.38538343-3...00000000
11187870디바이스이엔지-2730027950-6505-2.3317219474-100...00000000
12192440슈피겐코리아+4415043300+8502+1.9620554907-5...00000000
13210540디와이파워-1295013250-3005-2.261085831417-23...00000000
14225220제놀루션-1380014150-3505-2.4732068443+2...00000000
15352700씨앤투스성진-65406710-1705-2.534142272751-20...00000000
16950190미투젠-2020020500-3005-1.46691981398+1...00000000
17900280골든센츄리+363362+12+0.28674649243+1...00000000
18900250크리스탈신소재-14001430-305-2.1011719681657+1...00000000
\n", - "

19 rows × 63 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 종목명 현재가 기준가 전일대비 전일대비기호 등락율 거래량 거래대금 체결량 \\\n", - "0 900290 GRT 1225 1225 0 3 0.00 123651 152 -130 \n", - "1 900310 컬러레이 -1425 1465 -40 5 -2.73 147191 213 +294 \n", - "2 900340 윙입푸드 -1175 1215 -40 5 -3.29 187400 224 -144 \n", - "3 002170 삼양통상 -57500 57900 -400 5 -0.69 3467 201 -4 \n", - "4 017890 한국알콜 -11500 11600 -100 5 -0.86 56037 647 +1 \n", - "5 036190 금화피에스시 -30450 30800 -350 5 -1.14 3356 102 +1 \n", - "6 037710 광주신세계 171500 171500 0 3 0.00 510 88 -28 \n", - "7 049430 코메론 -10450 10600 -150 5 -1.42 20522 215 +2 \n", - "8 073560 우리손에프앤지 -2135 2150 -15 5 -0.70 162170 349 -170 \n", - "9 084650 랩지노믹스 -22900 23000 -100 5 -0.43 138975 3241 +1 \n", - "10 140910 에이리츠 +7930 7900 +30 2 +0.38 5383 43 -3 \n", - "11 187870 디바이스이엔지 -27300 27950 -650 5 -2.33 17219 474 -100 \n", - "12 192440 슈피겐코리아 +44150 43300 +850 2 +1.96 20554 907 -5 \n", - "13 210540 디와이파워 -12950 13250 -300 5 -2.26 108583 1417 -23 \n", - "14 225220 제놀루션 -13800 14150 -350 5 -2.47 32068 443 +2 \n", - "15 352700 씨앤투스성진 -6540 6710 -170 5 -2.53 414227 2751 -20 \n", - "16 950190 미투젠 -20200 20500 -300 5 -1.46 69198 1398 +1 \n", - "17 900280 골든센츄리 +363 362 +1 2 +0.28 674649 243 +1 \n", - "18 900250 크리스탈신소재 -1400 1430 -30 5 -2.10 1171968 1657 +1 \n", - "\n", - " ... ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가 로 \n", - "0 ... 00000000 \n", - "1 ... 00000000 \n", - "2 ... 00000000 \n", - "3 ... 00000000 \n", - "4 ... 00000000 \n", - "5 ... 00000000 \n", - "6 ... 00000000 \n", - "7 ... 00000000 \n", - "8 ... 00000000 \n", - "9 ... 00000000 \n", - "10 ... 00000000 \n", - "11 ... 00000000 \n", - "12 ... 00000000 \n", - "13 ... 00000000 \n", - "14 ... 00000000 \n", - "15 ... 00000000 \n", - "16 ... 00000000 \n", - "17 ... 00000000 \n", - "18 ... 00000000 \n", - "\n", - "[19 rows x 63 columns]" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "info" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "아니면 `stream` 생성시에 `with_info=True` 를 주는 경우 매 조건 이벤트마다 바로 뒤에 관심종목정보요청 이벤트를 이어서 반환하는데, 결국은 약간의 별도 데이터 처리가 필요하다." - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "condition_name = '중소형 저평가주'" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:25,992 [INFO] Start listening realtime condition stream... - :1\n" - ] - } - ], - "source": [ - "logging.info('Start listening realtime condition stream...')\n", - "stream = entrypoint.GetCodeListByConditionAsStream(condition_name, with_info=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "실시간 조건검색의 경우 조건에 만족/불만족하는 종목이 편입/이탈할때마다 계속해서 이벤트를 반환한다. 예시에서는 10초 동안만 이벤트를 확인해본다." - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [], - "source": [ - "import threading\n", - "\n", - "def stop_listening():\n", - " logging.info('Stop listening realtime condition events...')\n", - " stream.cancel()\n", - " \n", - "threading.Timer(10.0, stop_listening).start() # 10초 이후에 gRPC 커넥션 종료하도록 설정" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'arguments': [{'string_value': '9991'},\n", - " {'string_value': '900290;900310;900340;002170;017890;036190;037710;049430;073560;084650;140910;187870;192440;210540;225220;352700;950190;900280;900250;'},\n", - " {'string_value': '중소형 저평가주'},\n", - " {'long_value': '1'},\n", - " {'long_value': '0'}],\n", - " 'name': 'OnReceiveTrCondition'}\n", - "{'arguments': [{'string_value': '9991'},\n", - " {'string_value': '관심종목정보요청'},\n", - " {'string_value': 'OPTKWFID'},\n", - " {'string_value': ''},\n", - " {'string_value': '0'}],\n", - " 'multi_data': {'names': ['종목코드',\n", - " '종목명',\n", - " '현재가',\n", - " '기준가',\n", - " '전일대비',\n", - " '전일대비기호',\n", - " '등락율',\n", - " '거래량',\n", - " '거래대금',\n", - " '체결량',\n", - " '체결강도',\n", - " '전일거래량대비',\n", - " '매도호가',\n", - " '매수호가',\n", - " '매도1차호가',\n", - " '매도2차호가',\n", - " '매도3차호가',\n", - " '매도4차호가',\n", - " '매도5차호가',\n", - " '매수1차호가',\n", - " '매수2차호가',\n", - " '매수3차호가',\n", - " '매수4차호가',\n", - " '매수5차호가',\n", - " '상한가',\n", - " '하한가',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '종가',\n", - " '체결시간',\n", - " '예상체결가',\n", - " '예상체결량',\n", - " '자본금',\n", - " '액면가',\n", - " '시가총액',\n", - " '주식수',\n", - " '호가시간',\n", - " '일자',\n", - " '우선매도잔량',\n", - " '우선매수잔량',\n", - " '우선매도건수',\n", - " '우선매수건수',\n", - " '총매도잔량',\n", - " '총매수잔량',\n", - " '총매도건수',\n", - " '총매수건수',\n", - " '패리티',\n", - " '기어링',\n", - " '손익분기',\n", - " '자본지지',\n", - " 'ELW행사가',\n", - " '전환비율',\n", - " 'ELW만기일',\n", - " '미결제약정',\n", - " '미결제전일대비',\n", - " '이론가',\n", - " '내재변동성',\n", - " '델타',\n", - " '감마',\n", - " '쎄타',\n", - " '베가',\n", - " '로'],\n", - " 'values': [{'values': ['900290',\n", - " 'GRT',\n", - " '1225',\n", - " '1225',\n", - " '0',\n", - " '3',\n", - " '0.00',\n", - " '123651',\n", - " '152',\n", - " '-130',\n", - " '25.57',\n", - " '-17.52',\n", - " '+1230',\n", - " '1225',\n", - " '+1230',\n", - " '+1235',\n", - " '+1240',\n", - " '+1245',\n", - " '+1250',\n", - " '1225',\n", - " '-1220',\n", - " '-1215',\n", - " '-1210',\n", - " '-1205',\n", - " '+1590',\n", - " '-860',\n", - " '1225',\n", - " '+1230',\n", - " '1225',\n", - " '1225',\n", - " '142905',\n", - " '1225',\n", - " '535',\n", - " '770',\n", - " '0.00',\n", - " '825',\n", - " '67375',\n", - " '142905',\n", - " '20220118',\n", - " '30482',\n", - " '509886',\n", - " '',\n", - " '',\n", - " '187501',\n", - " '754859',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['900310',\n", - " '컬러레이',\n", - " '-1425',\n", - " '1465',\n", - " '-40',\n", - " '5',\n", - " '-2.73',\n", - " '147191',\n", - " '213',\n", - " '+294',\n", - " '38.29',\n", - " '+135.98',\n", - " '-1425',\n", - " '-1420',\n", - " '-1425',\n", - " '-1430',\n", - " '-1435',\n", - " '-1440',\n", - " '-1445',\n", - " '-1420',\n", - " '-1415',\n", - " '-1410',\n", - " '-1405',\n", - " '-1400',\n", - " '+1900',\n", - " '-1030',\n", - " '+1475',\n", - " '+1485',\n", - " '-1420',\n", - " '-1425',\n", - " '142810',\n", - " '+1475',\n", - " '69',\n", - " '336',\n", - " '0.00',\n", - " '770',\n", - " '54000',\n", - " '142834',\n", - " '20220118',\n", - " '36',\n", - " '10171',\n", - " '',\n", - " '',\n", - " '12441',\n", - " '56620',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['900340',\n", - " '윙입푸드',\n", - " '-1175',\n", - " '1215',\n", - " '-40',\n", - " '5',\n", - " '-3.29',\n", - " '187400',\n", - " '224',\n", - " '-144',\n", - " '60.89',\n", - " '+192.27',\n", - " '-1185',\n", - " '-1175',\n", - " '-1185',\n", - " '-1190',\n", - " '-1195',\n", - " '-1200',\n", - " '-1205',\n", - " '-1175',\n", - " '-1170',\n", - " '-1165',\n", - " '-1160',\n", - " '-1155',\n", - " '+1575',\n", - " '-855',\n", - " '1215',\n", - " '+1230',\n", - " '-1165',\n", - " '-1175',\n", - " '142850',\n", - " '1215',\n", - " '6',\n", - " '294',\n", - " '0.00',\n", - " '564',\n", - " '47973',\n", - " '142912',\n", - " '20220118',\n", - " '3102',\n", - " '5356',\n", - " '',\n", - " '',\n", - " '35173',\n", - " '30035',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['002170',\n", - " '삼양통상',\n", - " '-57500',\n", - " '57900',\n", - " '-400',\n", - " '5',\n", - " '-0.69',\n", - " '3467',\n", - " '201',\n", - " '-4',\n", - " '62.68',\n", - " '-54.14',\n", - " '-57600',\n", - " '-57500',\n", - " '-57600',\n", - " '-57700',\n", - " '-57800',\n", - " '57900',\n", - " '+58000',\n", - " '-57500',\n", - " '-57400',\n", - " '-57300',\n", - " '-57200',\n", - " '-57100',\n", - " '+75200',\n", - " '-40600',\n", - " '+58000',\n", - " '+58500',\n", - " '-57500',\n", - " '-57500',\n", - " '142838',\n", - " '+58000',\n", - " '2',\n", - " '150',\n", - " '5000',\n", - " '1725',\n", - " '3000',\n", - " '142905',\n", - " '20220118',\n", - " '222',\n", - " '19',\n", - " '',\n", - " '',\n", - " '7971',\n", - " '878',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['017890',\n", - " '한국알콜',\n", - " '-11500',\n", - " '11600',\n", - " '-100',\n", - " '5',\n", - " '-0.86',\n", - " '56037',\n", - " '647',\n", - " '+1',\n", - " '30.61',\n", - " '+126.56',\n", - " '-11500',\n", - " '-11450',\n", - " '-11500',\n", - " '-11550',\n", - " '11600',\n", - " '+11650',\n", - " '+11700',\n", - " '-11450',\n", - " '-11400',\n", - " '-11350',\n", - " '-11300',\n", - " '-11250',\n", - " '+15050',\n", - " '-8150',\n", - " '11600',\n", - " '+11750',\n", - " '-11400',\n", - " '-11500',\n", - " '142908',\n", - " '11600',\n", - " '898',\n", - " '108',\n", - " '500',\n", - " '2485',\n", - " '21606',\n", - " '142913',\n", - " '20220118',\n", - " '2351',\n", - " '2032',\n", - " '',\n", - " '',\n", - " '22942',\n", - " '20124',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['036190',\n", - " '금화피에스시',\n", - " '-30450',\n", - " '30800',\n", - " '-350',\n", - " '5',\n", - " '-1.14',\n", - " '3356',\n", - " '102',\n", - " '+1',\n", - " '30.63',\n", - " '-91.29',\n", - " '-30450',\n", - " '-30350',\n", - " '-30450',\n", - " '-30500',\n", - " '-30550',\n", - " '-30600',\n", - " '-30650',\n", - " '-30350',\n", - " '-30200',\n", - " '-30150',\n", - " '-30100',\n", - " '-30050',\n", - " '+40000',\n", - " '-21600',\n", - " '-30750',\n", - " '30800',\n", - " '-30200',\n", - " '-30450',\n", - " '142555',\n", - " '-30750',\n", - " '4',\n", - " '30',\n", - " '500',\n", - " '1827',\n", - " '6000',\n", - " '142607',\n", - " '20220118',\n", - " '35',\n", - " '2',\n", - " '',\n", - " '',\n", - " '2160',\n", - " '2879',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['037710',\n", - " '광주신세계',\n", - " '171500',\n", - " '171500',\n", - " '0',\n", - " '3',\n", - " '0.00',\n", - " '510',\n", - " '88',\n", - " '-28',\n", - " '44.60',\n", - " '-58.76',\n", - " '171500',\n", - " '-171000',\n", - " '171500',\n", - " '+172000',\n", - " '+172500',\n", - " '+173000',\n", - " '+173500',\n", - " '-171000',\n", - " '-170500',\n", - " '-170000',\n", - " '-169500',\n", - " '-169000',\n", - " '+222500',\n", - " '-120500',\n", - " '171500',\n", - " '+173000',\n", - " '-171000',\n", - " '171500',\n", - " '142825',\n", - " '171500',\n", - " '1',\n", - " '80',\n", - " '5000',\n", - " '2744',\n", - " '1600',\n", - " '142914',\n", - " '20220118',\n", - " '6',\n", - " '167',\n", - " '',\n", - " '',\n", - " '326',\n", - " '581',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['049430',\n", - " '코메론',\n", - " '-10450',\n", - " '10600',\n", - " '-150',\n", - " '5',\n", - " '-1.42',\n", - " '20522',\n", - " '215',\n", - " '+2',\n", - " '75.92',\n", - " '-62.99',\n", - " '-10450',\n", - " '-10400',\n", - " '-10450',\n", - " '-10500',\n", - " '-10550',\n", - " '10600',\n", - " '+10650',\n", - " '-10400',\n", - " '-10350',\n", - " '-10300',\n", - " '-10250',\n", - " '-10200',\n", - " '+13750',\n", - " '-7450',\n", - " '10600',\n", - " '+10650',\n", - " '-10350',\n", - " '-10450',\n", - " '142851',\n", - " '10600',\n", - " '54',\n", - " '45',\n", - " '500',\n", - " '946',\n", - " '9048',\n", - " '142851',\n", - " '20220118',\n", - " '256',\n", - " '3',\n", - " '',\n", - " '',\n", - " '3616',\n", - " '29091',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['073560',\n", - " '우리손에프앤지',\n", - " '-2135',\n", - " '2150',\n", - " '-15',\n", - " '5',\n", - " '-0.70',\n", - " '162170',\n", - " '349',\n", - " '-170',\n", - " '34.01',\n", - " '-41.38',\n", - " '-2140',\n", - " '-2130',\n", - " '-2140',\n", - " '-2145',\n", - " '2150',\n", - " '+2155',\n", - " '+2160',\n", - " '-2130',\n", - " '-2125',\n", - " '-2120',\n", - " '-2115',\n", - " '-2110',\n", - " '+2795',\n", - " '-1505',\n", - " '-2145',\n", - " '+2170',\n", - " '-2130',\n", - " '-2135',\n", - " '142750',\n", - " '-2145',\n", - " '1777',\n", - " '346',\n", - " '500',\n", - " '1478',\n", - " '69238',\n", - " '142750',\n", - " '20220118',\n", - " '140',\n", - " '3176',\n", - " '',\n", - " '',\n", - " '44163',\n", - " '80317',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['084650',\n", - " '랩지노믹스',\n", - " '-22900',\n", - " '23000',\n", - " '-100',\n", - " '5',\n", - " '-0.43',\n", - " '138975',\n", - " '3241',\n", - " '+1',\n", - " '69.13',\n", - " '-87.60',\n", - " '-22900',\n", - " '-22850',\n", - " '-22900',\n", - " '-22950',\n", - " '23000',\n", - " '+23050',\n", - " '+23100',\n", - " '-22850',\n", - " '-22800',\n", - " '-22750',\n", - " '-22700',\n", - " '-22650',\n", - " '+29900',\n", - " '-16100',\n", - " '23000',\n", - " '+23750',\n", - " '-22800',\n", - " '-22900',\n", - " '142921',\n", - " '23000',\n", - " '6118',\n", - " '57',\n", - " '500',\n", - " '2622',\n", - " '11450',\n", - " '142921',\n", - " '20220118',\n", - " '852',\n", - " '930',\n", - " '',\n", - " '',\n", - " '5683',\n", - " '15214',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['140910',\n", - " '에이리츠',\n", - " '+7930',\n", - " '7900',\n", - " '+30',\n", - " '2',\n", - " '+0.38',\n", - " '5383',\n", - " '43',\n", - " '-3',\n", - " '151.92',\n", - " '-32.82',\n", - " '+7940',\n", - " '+7930',\n", - " '+7940',\n", - " '+7970',\n", - " '+7990',\n", - " '+8030',\n", - " '+8040',\n", - " '+7930',\n", - " '+7920',\n", - " '+7910',\n", - " '7900',\n", - " '-7890',\n", - " '+10250',\n", - " '-5530',\n", - " '7900',\n", - " '+8200',\n", - " '7900',\n", - " '+7930',\n", - " '142341',\n", - " '7900',\n", - " '12',\n", - " '211',\n", - " '5000',\n", - " '334',\n", - " '4217',\n", - " '142341',\n", - " '20220118',\n", - " '683',\n", - " '15',\n", - " '',\n", - " '',\n", - " '953',\n", - " '4310',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['187870',\n", - " '디바이스이엔지',\n", - " '-27300',\n", - " '27950',\n", - " '-650',\n", - " '5',\n", - " '-2.33',\n", - " '17219',\n", - " '474',\n", - " '-100',\n", - " '31.97',\n", - " '+131.63',\n", - " '-27350',\n", - " '-27300',\n", - " '-27350',\n", - " '-27400',\n", - " '-27450',\n", - " '-27500',\n", - " '-27550',\n", - " '-27300',\n", - " '-27250',\n", - " '-27200',\n", - " '-27150',\n", - " '-27100',\n", - " '+36300',\n", - " '-19600',\n", - " '-27600',\n", - " '+28050',\n", - " '-27250',\n", - " '-27300',\n", - " '142830',\n", - " '-27600',\n", - " '374',\n", - " '35',\n", - " '500',\n", - " '1921',\n", - " '7037',\n", - " '142913',\n", - " '20220118',\n", - " '955',\n", - " '451',\n", - " '',\n", - " '',\n", - " '4104',\n", - " '3041',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['192440',\n", - " '슈피겐코리아',\n", - " '+44150',\n", - " '43300',\n", - " '+850',\n", - " '2',\n", - " '+1.96',\n", - " '20554',\n", - " '907',\n", - " '-5',\n", - " '139.80',\n", - " '+174.04',\n", - " '+44200',\n", - " '+44150',\n", - " '+44200',\n", - " '+44250',\n", - " '+44300',\n", - " '+44350',\n", - " '+44400',\n", - " '+44150',\n", - " '+44100',\n", - " '+44050',\n", - " '+44000',\n", - " '+43950',\n", - " '+56200',\n", - " '-30350',\n", - " '-43200',\n", - " '+44600',\n", - " '-43150',\n", - " '+44150',\n", - " '142921',\n", - " '-43200',\n", - " '281',\n", - " '31',\n", - " '500',\n", - " '2745',\n", - " '6216',\n", - " '142921',\n", - " '20220118',\n", - " '115',\n", - " '97',\n", - " '',\n", - " '',\n", - " '4084',\n", - " '1215',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['210540',\n", - " '디와이파워',\n", - " '-12950',\n", - " '13250',\n", - " '-300',\n", - " '5',\n", - " '-2.26',\n", - " '108583',\n", - " '1417',\n", - " '-23',\n", - " '12.78',\n", - " '+173.32',\n", - " '-13000',\n", - " '-12950',\n", - " '-13000',\n", - " '-13050',\n", - " '-13100',\n", - " '-13150',\n", - " '-13200',\n", - " '-12950',\n", - " '-12900',\n", - " '-12850',\n", - " '-12800',\n", - " '-12750',\n", - " '+17200',\n", - " '-9300',\n", - " '13250',\n", - " '+13350',\n", - " '-12950',\n", - " '-12950',\n", - " '142901',\n", - " '13250',\n", - " '23',\n", - " '55',\n", - " '500',\n", - " '1430',\n", - " '11042',\n", - " '142901',\n", - " '20220118',\n", - " '1165',\n", - " '2762',\n", - " '',\n", - " '',\n", - " '29442',\n", - " '26833',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['225220',\n", - " '제놀루션',\n", - " '-13800',\n", - " '14150',\n", - " '-350',\n", - " '5',\n", - " '-2.47',\n", - " '32068',\n", - " '443',\n", - " '+2',\n", - " '22.44',\n", - " '-65.12',\n", - " '-13800',\n", - " '-13700',\n", - " '-13800',\n", - " '-13850',\n", - " '-13900',\n", - " '-13950',\n", - " '-14000',\n", - " '-13700',\n", - " '-13650',\n", - " '-13600',\n", - " '-13550',\n", - " '-13500',\n", - " '+18350',\n", - " '-9950',\n", - " '14150',\n", - " '14150',\n", - " '-13700',\n", - " '-13800',\n", - " '142725',\n", - " '14150',\n", - " '110',\n", - " '48',\n", - " '500',\n", - " '1320',\n", - " '9567',\n", - " '142845',\n", - " '20220118',\n", - " '440',\n", - " '427',\n", - " '',\n", - " '',\n", - " '5911',\n", - " '7650',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['352700',\n", - " '씨앤투스성진',\n", - " '-6540',\n", - " '6710',\n", - " '-170',\n", - " '5',\n", - " '-2.53',\n", - " '414227',\n", - " '2751',\n", - " '-20',\n", - " '49.09',\n", - " '-63.02',\n", - " '-6550',\n", - " '-6540',\n", - " '-6550',\n", - " '-6560',\n", - " '-6570',\n", - " '-6580',\n", - " '-6590',\n", - " '-6540',\n", - " '-6530',\n", - " '-6520',\n", - " '-6510',\n", - " '-6500',\n", - " '+8720',\n", - " '-4700',\n", - " '6710',\n", - " '+6770',\n", - " '-6520',\n", - " '-6540',\n", - " '142924',\n", - " '6710',\n", - " '4257',\n", - " '143',\n", - " '500',\n", - " '1849',\n", - " '28277',\n", - " '142924',\n", - " '20220118',\n", - " '1936',\n", - " '179',\n", - " '',\n", - " '',\n", - " '15891',\n", - " '48036',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['950190',\n", - " '미투젠',\n", - " '-20200',\n", - " '20500',\n", - " '-300',\n", - " '5',\n", - " '-1.46',\n", - " '69198',\n", - " '1398',\n", - " '+1',\n", - " '67.76',\n", - " '-78.33',\n", - " '-20200',\n", - " '-20100',\n", - " '-20200',\n", - " '-20300',\n", - " '-20350',\n", - " '-20400',\n", - " '-20450',\n", - " '-20100',\n", - " '-20050',\n", - " '-20000',\n", - " '-19950',\n", - " '-19900',\n", - " '+26650',\n", - " '-14350',\n", - " '20500',\n", - " '+20550',\n", - " '-19950',\n", - " '-20200',\n", - " '142708',\n", - " '20500',\n", - " '553',\n", - " '0',\n", - " '0',\n", - " '2743',\n", - " '13580',\n", - " '142919',\n", - " '20220118',\n", - " '760',\n", - " '21',\n", - " '',\n", - " '',\n", - " '8086',\n", - " '9052',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['900280',\n", - " '골든센츄리',\n", - " '+363',\n", - " '362',\n", - " '+1',\n", - " '2',\n", - " '+0.28',\n", - " '674649',\n", - " '243',\n", - " '+1',\n", - " '81.03',\n", - " '+150.12',\n", - " '+363',\n", - " '362',\n", - " '+363',\n", - " '+364',\n", - " '+365',\n", - " '+366',\n", - " '+367',\n", - " '362',\n", - " '-361',\n", - " '-360',\n", - " '-359',\n", - " '-358',\n", - " '+470',\n", - " '-254',\n", - " '362',\n", - " '+365',\n", - " '-358',\n", - " '+363',\n", - " '142834',\n", - " '362',\n", - " '592',\n", - " '35',\n", - " '0.20',\n", - " '641',\n", - " '176574',\n", - " '142834',\n", - " '20220118',\n", - " '10931',\n", - " '12647',\n", - " '',\n", - " '',\n", - " '71073',\n", - " '184853',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']},\n", - " {'values': ['900250',\n", - " '크리스탈신소재',\n", - " '-1400',\n", - " '1430',\n", - " '-30',\n", - " '5',\n", - " '-2.10',\n", - " '1171968',\n", - " '1657',\n", - " '+1',\n", - " '37.44',\n", - " '-61.96',\n", - " '-1400',\n", - " '-1390',\n", - " '-1400',\n", - " '-1405',\n", - " '-1410',\n", - " '-1415',\n", - " '-1420',\n", - " '-1390',\n", - " '-1385',\n", - " '-1380',\n", - " '-1375',\n", - " '-1370',\n", - " '+1855',\n", - " '-1005',\n", - " '+1435',\n", - " '+1445',\n", - " '-1385',\n", - " '-1400',\n", - " '142920',\n", - " '+1435',\n", - " '5363',\n", - " '36',\n", - " '0.50',\n", - " '1006',\n", - " '71831',\n", - " '142920',\n", - " '20220118',\n", - " '3351',\n", - " '30868',\n", - " '',\n", - " '',\n", - " '123110',\n", - " '189904',\n", - " '0',\n", - " '',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0.00',\n", - " '0',\n", - " '0.0000',\n", - " '00000000',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '',\n", - " '']}]},\n", - " 'name': 'OnReceiveTrData'}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:36,025 [INFO] Stop listening realtime condition events... - :4\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "<_MultiThreadedRendezvous of RPC that terminated with:\n", - "\tstatus = StatusCode.CANCELLED\n", - "\tdetails = \"Locally cancelled by application!\"\n", - "\tdebug_error_string = \"None\"\n", - ">\n" - ] - } - ], - "source": [ - "import grpc\n", - "\n", - "events = []\n", - "\n", - "try:\n", - " for event in stream:\n", - " events.append(event)\n", - " pprint_event(event)\n", - "except grpc.RpcError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [], - "source": [ - "condition_event = events[0]\n", - "info_event = events[1]\n", - "\n", - "records = [values.values for values in info_event.multi_data.values]\n", - "columns = info_event.multi_data.names\n", - "\n", - "info = pd.DataFrame.from_records(records, columns=columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
종목코드종목명현재가기준가전일대비전일대비기호등락율거래량거래대금체결량...ELW만기일미결제약정미결제전일대비이론가내재변동성델타감마쎄타베가로
0900290GRT12251225030.00123651152-130...00000000
1900310컬러레이-14251465-405-2.73147191213+294...00000000
2900340윙입푸드-11751215-405-3.29187400224-144...00000000
3002170삼양통상-5750057900-4005-0.693467201-4...00000000
4017890한국알콜-1150011600-1005-0.8656037647+1...00000000
5036190금화피에스시-3045030800-3505-1.143356102+1...00000000
6037710광주신세계171500171500030.0051088-28...00000000
7049430코메론-1045010600-1505-1.4220522215+2...00000000
8073560우리손에프앤지-21352150-155-0.70162170349-170...00000000
9084650랩지노믹스-2290023000-1005-0.431389753241+1...00000000
10140910에이리츠+79307900+302+0.38538343-3...00000000
11187870디바이스이엔지-2730027950-6505-2.3317219474-100...00000000
12192440슈피겐코리아+4415043300+8502+1.9620554907-5...00000000
13210540디와이파워-1295013250-3005-2.261085831417-23...00000000
14225220제놀루션-1380014150-3505-2.4732068443+2...00000000
15352700씨앤투스성진-65406710-1705-2.534142272751-20...00000000
16950190미투젠-2020020500-3005-1.46691981398+1...00000000
17900280골든센츄리+363362+12+0.28674649243+1...00000000
18900250크리스탈신소재-14001430-305-2.1011719681657+1...00000000
\n", - "

19 rows × 63 columns

\n", - "
" - ], - "text/plain": [ - " 종목코드 종목명 현재가 기준가 전일대비 전일대비기호 등락율 거래량 거래대금 체결량 \\\n", - "0 900290 GRT 1225 1225 0 3 0.00 123651 152 -130 \n", - "1 900310 컬러레이 -1425 1465 -40 5 -2.73 147191 213 +294 \n", - "2 900340 윙입푸드 -1175 1215 -40 5 -3.29 187400 224 -144 \n", - "3 002170 삼양통상 -57500 57900 -400 5 -0.69 3467 201 -4 \n", - "4 017890 한국알콜 -11500 11600 -100 5 -0.86 56037 647 +1 \n", - "5 036190 금화피에스시 -30450 30800 -350 5 -1.14 3356 102 +1 \n", - "6 037710 광주신세계 171500 171500 0 3 0.00 510 88 -28 \n", - "7 049430 코메론 -10450 10600 -150 5 -1.42 20522 215 +2 \n", - "8 073560 우리손에프앤지 -2135 2150 -15 5 -0.70 162170 349 -170 \n", - "9 084650 랩지노믹스 -22900 23000 -100 5 -0.43 138975 3241 +1 \n", - "10 140910 에이리츠 +7930 7900 +30 2 +0.38 5383 43 -3 \n", - "11 187870 디바이스이엔지 -27300 27950 -650 5 -2.33 17219 474 -100 \n", - "12 192440 슈피겐코리아 +44150 43300 +850 2 +1.96 20554 907 -5 \n", - "13 210540 디와이파워 -12950 13250 -300 5 -2.26 108583 1417 -23 \n", - "14 225220 제놀루션 -13800 14150 -350 5 -2.47 32068 443 +2 \n", - "15 352700 씨앤투스성진 -6540 6710 -170 5 -2.53 414227 2751 -20 \n", - "16 950190 미투젠 -20200 20500 -300 5 -1.46 69198 1398 +1 \n", - "17 900280 골든센츄리 +363 362 +1 2 +0.28 674649 243 +1 \n", - "18 900250 크리스탈신소재 -1400 1430 -30 5 -2.10 1171968 1657 +1 \n", - "\n", - " ... ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가 로 \n", - "0 ... 00000000 \n", - "1 ... 00000000 \n", - "2 ... 00000000 \n", - "3 ... 00000000 \n", - "4 ... 00000000 \n", - "5 ... 00000000 \n", - "6 ... 00000000 \n", - "7 ... 00000000 \n", - "8 ... 00000000 \n", - "9 ... 00000000 \n", - "10 ... 00000000 \n", - "11 ... 00000000 \n", - "12 ... 00000000 \n", - "13 ... 00000000 \n", - "14 ... 00000000 \n", - "15 ... 00000000 \n", - "16 ... 00000000 \n", - "17 ... 00000000 \n", - "18 ... 00000000 \n", - "\n", - "[19 rows x 63 columns]" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "info" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6. 주문처리 예시" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "first_account_no = entrypoint.GetFirstAvailableAccount()" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "request_name = \"삼성전자 1주 시장가 신규 매수\" # 사용자 구분명, 구분가능한 임의의 문자열\n", - "screen_no = \"0001\" # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당\n", - "account_no = first_account_no # 계좌번호 10자리, 여기서는 계좌번호 목록에서 첫번째로 발견한 계좌번호로 매수처리\n", - "order_type = 1 # 주문유형, 1 : 신규매수\n", - "code = samsung_code # 종목코드, 앞의 삼성전자 종목코드\n", - "quantity = 1 # 주문수량, 1주 매수\n", - "price = 0 # 주문가격, 시장가 매수는 가격설정 의미없음\n", - "quote_type = \"03\" # 거래구분, 03 : 시장가\n", - "original_order_no = \"\" # 원주문번호, 주문 정정/취소 등에서 사용" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "주문유형 및 거래구분 등과 관련된 자세한 정보들은 [KOAStudio](https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf#page=7) 프로그램에서 확인할 수 있다." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "주문처리는 실제 시장이 열려있는 동안에만 테스트해볼 수 있기 때문에, 현재 장이 열려 있는지 먼저 확인하고 해당 경우에 한정해서 테스트를 진행한다." - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "from pandas import Timestamp\n", - "from exchange_calendars import get_calendar\n", - "\n", - "krx_calendar = get_calendar('XKRX')\n", - "\n", - "def is_currently_in_session():\n", - " calendar = krx_calendar\n", - " now = Timestamp.now(calendar.tz).floor(\"T\")\n", - " previous_open = calendar.previous_open(now).astimezone(calendar.tz)\n", - " next_close = calendar.next_close(previous_open).astimezone(calendar.tz)\n", - " return previous_open <= now <= next_close" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:41,362 [INFO] Sending order to buy 005930, quantity of 1 stock, at market price... - :2\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'arguments': [{'string_value': '0001'},\n", - " {'string_value': '삼성전자 1주 시장가 신규 매수'},\n", - " {'string_value': 'KOA_NORMAL_BUY_KP_ORD'},\n", - " {'string_value': '[100000] 모의투자 매수주문완료'}],\n", - " 'name': 'OnReceiveMsg'}\n", - "{'arguments': [{'string_value': '0001'},\n", - " {'string_value': '삼성전자 1주 시장가 신규 매수'},\n", - " {'string_value': 'KOA_NORMAL_BUY_KP_ORD'},\n", - " {'string_value': ''},\n", - " {'string_value': ''}],\n", - " 'name': 'OnReceiveTrData',\n", - " 'single_data': {'names': ['주문번호'], 'values': ['0163911']}}\n", - "{'arguments': [{'string_value': '0'},\n", - " {'long_value': '35'},\n", - " {'string_value': '9201;9203;9205;9001;912;913;302;900;901;902;903;904;905;906;907;908;909;910;911;10;27;28;914;915;938;939;919;920;921;922;923;949;10010;969;819'}],\n", - " 'name': 'OnReceiveChejanData',\n", - " 'single_data': {'names': ['계좌번호',\n", - " '주문번호',\n", - " '관리사번',\n", - " '종목코드',\n", - " '업무구분',\n", - " '주문상태',\n", - " '종목명',\n", - " '주문수량',\n", - " '주문가격',\n", - " '미체결수량',\n", - " '체결누계금액',\n", - " '원주문번호',\n", - " '주문구분',\n", - " '매매구분',\n", - " '매도수구분',\n", - " '주문/체결시간',\n", - " '체결번호',\n", - " '체결가',\n", - " '체결량',\n", - " '현재가',\n", - " '매도호가',\n", - " '매수호가',\n", - " '단위체결가',\n", - " '단위체결량',\n", - " '당일매매수수료',\n", - " '당일매매세금',\n", - " '919',\n", - " '920',\n", - " '921',\n", - " '922',\n", - " '923',\n", - " '949',\n", - " '시간외단일가_현재가',\n", - " '969',\n", - " '819'],\n", - " 'values': ['8014526011',\n", - " '0163911',\n", - " '',\n", - " 'A005930',\n", - " 'JJ',\n", - " '접수',\n", - " '삼성전자',\n", - " '1',\n", - " '0',\n", - " '1',\n", - " '0',\n", - " '0000000',\n", - " '+매수',\n", - " '시장가',\n", - " '2',\n", - " '142940',\n", - " '',\n", - " '',\n", - " '',\n", - " '-77000',\n", - " '-77100',\n", - " '-77000',\n", - " '',\n", - " '',\n", - " '0',\n", - " '0',\n", - " '0',\n", - " '0001',\n", - " '',\n", - " '00',\n", - " '00000000',\n", - " '3',\n", - " '-77300',\n", - " '0',\n", - " '0']}}\n", - "{'arguments': [{'string_value': '0'},\n", - " {'long_value': '35'},\n", - " {'string_value': '9201;9203;9205;9001;912;913;302;900;901;902;903;904;905;906;907;908;909;910;911;10;27;28;914;915;938;939;919;920;921;922;923;949;10010;969;819'}],\n", - " 'name': 'OnReceiveChejanData',\n", - " 'single_data': {'names': ['계좌번호',\n", - " '주문번호',\n", - " '관리사번',\n", - " '종목코드',\n", - " '업무구분',\n", - " '주문상태',\n", - " '종목명',\n", - " '주문수량',\n", - " '주문가격',\n", - " '미체결수량',\n", - " '체결누계금액',\n", - " '원주문번호',\n", - " '주문구분',\n", - " '매매구분',\n", - " '매도수구분',\n", - " '주문/체결시간',\n", - " '체결번호',\n", - " '체결가',\n", - " '체결량',\n", - " '현재가',\n", - " '매도호가',\n", - " '매수호가',\n", - " '단위체결가',\n", - " '단위체결량',\n", - " '당일매매수수료',\n", - " '당일매매세금',\n", - " '919',\n", - " '920',\n", - " '921',\n", - " '922',\n", - " '923',\n", - " '949',\n", - " '시간외단일가_현재가',\n", - " '969',\n", - " '819'],\n", - " 'values': ['8014526011',\n", - " '0163911',\n", - " '',\n", - " 'A005930',\n", - " 'JJ',\n", - " '체결',\n", - " '삼성전자',\n", - " '1',\n", - " '0',\n", - " '0',\n", - " '77000',\n", - " '0000000',\n", - " '+매수',\n", - " '시장가',\n", - " '2',\n", - " '142941',\n", - " '1234931',\n", - " '77000',\n", - " '1',\n", - " '-77000',\n", - " '-77100',\n", - " '-77000',\n", - " '77000',\n", - " '1',\n", - " '260',\n", - " '0',\n", - " '0',\n", - " '0001',\n", - " '',\n", - " '00',\n", - " '00000000',\n", - " '3',\n", - " '-77300',\n", - " '0',\n", - " '0']}}\n", - "{'arguments': [{'string_value': '1'},\n", - " {'long_value': '34'},\n", - " {'string_value': '9201;9001;917;916;302;10;930;931;932;933;945;946;950;951;27;28;307;8019;957;958;918;990;991;992;993;959;924;10010;25;11;12;306;305;970'}],\n", - " 'name': 'OnReceiveChejanData',\n", - " 'single_data': {'names': ['계좌번호',\n", - " '종목코드',\n", - " '신용구분',\n", - " '대출일',\n", - " '종목명',\n", - " '현재가',\n", - " '보유수량',\n", - " '매입단가',\n", - " '총매입가',\n", - " '주문가능수량',\n", - " '당일순매수량',\n", - " '매도/매수구분',\n", - " '당일총매도손익',\n", - " '예수금',\n", - " '매도호가',\n", - " '매수호가',\n", - " '기준가',\n", - " '손익율',\n", - " '신용금액',\n", - " '신용이자',\n", - " '만기일',\n", - " '990',\n", - " '991',\n", - " '992',\n", - " '993',\n", - " '담보대출수량',\n", - " '924',\n", - " '시간외단일가_현재가',\n", - " '전일대비기호',\n", - " '전일대비',\n", - " '등락율',\n", - " '하한가',\n", - " '상한가',\n", - " '970'],\n", - " 'values': ['8014526011',\n", - " 'A005930',\n", - " '00',\n", - " '00000000',\n", - " '삼성전자',\n", - " '-77000',\n", - " '2',\n", - " '77150',\n", - " '154300',\n", - " '2',\n", - " '1',\n", - " '2',\n", - " '0',\n", - " '0',\n", - " '-77100',\n", - " '-77000',\n", - " '77500',\n", - " '0.00',\n", - " '0',\n", - " '0',\n", - " '00000000',\n", - " '0',\n", - " '0.00',\n", - " '0',\n", - " '0.00',\n", - " '0',\n", - " '0',\n", - " '-77300',\n", - " '5',\n", - " '-500',\n", - " '-0.65',\n", - " '-54300',\n", - " '+100500',\n", - " '10']}}\n" - ] - } - ], - "source": [ - "if is_currently_in_session():\n", - " logging.info('Sending order to buy %s, quantity of 1 stock, at market price...', code)\n", - " for event in entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no):\n", - " pprint_event(event)\n", - "else:\n", - " logging.info('Cannot send an order while market is not open, skipping...')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "주문 이벤트는 기본적으로 주문수량이 모두 소진되기 전까지 이벤트를 듣도록 되어있으며, 다른 이벤트 스트림과 동일하게 `stream.cancel()` 의 형태로 이벤트 스트림을 더이상 듣지 않도록 하는것이 가능하다. 다만 이벤트 스트림을 취소하는 것이 기존 주문까지 취소하는 것은 아니기 때문에 주문취소나 정정등을 위해서는 별도의 취소/정정 주문을 넣어줘야 한다.\n", - "\n", - "여기서 반환되는 이벤트 객체 역시 앞선 TR 예시에서와 동일하게 `ListenResponse` 타입의 gRPC 메시지 형태로 반환된다. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7. 실시간 데이터 처리 예시" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [], - "source": [ - "from koapy import KiwoomOpenApiPlusRealType" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [], - "source": [ - "code_list = [code]\n", - "fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name('주식시세')\n", - "opt_type = '0' # 기존 화면에 추가가 아니라 신규 생성, 1 의 경우 기존 화면번호에 추가" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:43,322 [INFO] Start listening realtime stock data for code: 005930 - :1\n" - ] - } - ], - "source": [ - "logging.info('Start listening realtime stock data for code: %s', code)\n", - "stream = entrypoint.GetRealDataForCodesAsStream(\n", - " code_list,\n", - " fid_list,\n", - " opt_type,\n", - " screen_no=None, # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당\n", - " infer_fids=True, # True 로 설정 시 주어진 fid_list 를 고집하지 말고 이벤트 처리 함수의 인자로 전달받는 실시간데이터 이름에 따라 유연하게 fid_list 를 추론\n", - " readable_names=True, # True 로 설정 시 각 fid 마다 숫자 대신 읽을 수 있는 이름으로 변환하여 반환\n", - " fast_parse=False, # True 로 설정 시 이벤트 처리 함수내에서 데이터 값 읽기 시 GetCommRealData() 함수 호출 대신, 이벤트 처리 함수의 인자로 넘어오는 데이터를 직접 활용, infer_fids 가 True 로 설정된 경우만 유의미함\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [], - "source": [ - "import threading\n", - "\n", - "def stop_listening():\n", - " logging.info('Stop listening realtime events...')\n", - " stream.cancel()\n", - " \n", - "threading.Timer(10.0, stop_listening).start() # 10초 이후에 gRPC 커넥션 종료하도록 설정" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142942\\t-77100\\t-400\\t-0.52\\t-77100\\t-76900\\t'\n", - " '+3\\t7884712\\t608869\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900410\\t-70033816000\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4602702\\t2\\t0\\t-89.68\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817707\\t'\n", - " '2944634\\t-37.93\\t30338\\t31739\\t+231\\t 0\\t+3\\t'\n", - " '+3\\t30840\\t24672\\t77222\\t411'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142942',\n", - " '-77100',\n", - " '-400',\n", - " '-0.52',\n", - " '-77100',\n", - " '-76900',\n", - " '+3',\n", - " '7884712',\n", - " '608869',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900410',\n", - " '-70033816000',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4602702',\n", - " '2',\n", - " '0',\n", - " '-89.68',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817707',\n", - " '2944634',\n", - " '-37.93',\n", - " '30338',\n", - " '31739',\n", - " '+231',\n", - " ' 0',\n", - " '+3',\n", - " '+3',\n", - " '30840',\n", - " '24672',\n", - " '77222',\n", - " '411']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식우선호가'},\n", - " {'string_value': '-77000\\t-76900'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['매도호가', '매수호가'], 'values': ['-77000', '-76900']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식우선호가'},\n", - " {'string_value': '-77100\\t-77000'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['매도호가', '매수호가'], 'values': ['-77100', '-77000']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142943\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '+20\\t7884732\\t608871\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900390\\t-70032276000\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4596733\\t2\\t0\\t-89.68\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817707\\t'\n", - " '2944654\\t-37.94\\t30338\\t31740\\t+1540\\t 0\\t'\n", - " '+20\\t+20\\t30800\\t24640\\t77222\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142943',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '+20',\n", - " '7884732',\n", - " '608871',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900390',\n", - " '-70032276000',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.68',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817707',\n", - " '2944654',\n", - " '-37.94',\n", - " '30338',\n", - " '31740',\n", - " '+1540',\n", - " ' 0',\n", - " '+20',\n", - " '+20',\n", - " '30800',\n", - " '24640',\n", - " '77222',\n", - " '410']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142945\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '-262\\t7884994\\t608891\\t+77600\\t+77800\\t'\n", - " '-76600\\t5\\t-900128\\t-70012102000\\t-89.75\\t'\n", - " '0.13\\t201\\t61.12\\t4596733\\t2\\t0\\t-89.69\\t'\n", - " '000000\\t000000\\t11814\\t090003\\t100015\\t'\n", - " '133453\\t4817969\\t2944654\\t-37.93\\t30339\\t'\n", - " '31740\\t-20174\\t-262\\t 0\\t-262\\t30800\\t24640\\t'\n", - " '77221\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142945',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '-262',\n", - " '7884994',\n", - " '608891',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900128',\n", - " '-70012102000',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817969',\n", - " '2944654',\n", - " '-37.93',\n", - " '30339',\n", - " '31740',\n", - " '-20174',\n", - " '-262',\n", - " ' 0',\n", - " '-262',\n", - " '30800',\n", - " '24640',\n", - " '77221',\n", - " '410']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142945\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '-3\\t7884997\\t608891\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900125\\t-70011871000\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4596733\\t2\\t0\\t-89.69\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817972\\t'\n", - " '2944654\\t-37.93\\t30340\\t31740\\t-231\\t-3\\t 0\\t'\n", - " '-3\\t30800\\t24640\\t77221\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142945',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '-3',\n", - " '7884997',\n", - " '608891',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900125',\n", - " '-70011871000',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817972',\n", - " '2944654',\n", - " '-37.93',\n", - " '30340',\n", - " '31740',\n", - " '-231',\n", - " '-3',\n", - " ' 0',\n", - " '-3',\n", - " '30800',\n", - " '24640',\n", - " '77221',\n", - " '410']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142946\\t-77100\\t-400\\t-0.52\\t-77100\\t-77000\\t'\n", - " '+3\\t7885000\\t608891\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900122\\t-70011639700\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4602702\\t2\\t0\\t-89.69\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817972\\t'\n", - " '2944657\\t-37.93\\t30340\\t31741\\t+231\\t 0\\t+3\\t'\n", - " '+3\\t30840\\t24672\\t77221\\t411'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142946',\n", - " '-77100',\n", - " '-400',\n", - " '-0.52',\n", - " '-77100',\n", - " '-77000',\n", - " '+3',\n", - " '7885000',\n", - " '608891',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900122',\n", - " '-70011639700',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4602702',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817972',\n", - " '2944657',\n", - " '-37.93',\n", - " '30340',\n", - " '31741',\n", - " '+231',\n", - " ' 0',\n", - " '+3',\n", - " '+3',\n", - " '30840',\n", - " '24672',\n", - " '77221',\n", - " '411']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142946\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '-1\\t7885001\\t608892\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900121\\t-70011562700\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4596733\\t2\\t0\\t-89.69\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817973\\t'\n", - " '2944657\\t-37.93\\t30341\\t31741\\t-77\\t-1\\t 0\\t'\n", - " '-1\\t30800\\t24640\\t77221\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142946',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '-1',\n", - " '7885001',\n", - " '608892',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900121',\n", - " '-70011562700',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817973',\n", - " '2944657',\n", - " '-37.93',\n", - " '30341',\n", - " '31741',\n", - " '-77',\n", - " '-1',\n", - " ' 0',\n", - " '-1',\n", - " '30800',\n", - " '24640',\n", - " '77221',\n", - " '410']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142947\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '-10\\t7885011\\t608892\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900111\\t-70010792700\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4596733\\t2\\t0\\t-89.69\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817983\\t'\n", - " '2944657\\t-37.93\\t30342\\t31741\\t-770\\t-10\\t 0\\t'\n", - " '-10\\t30800\\t24640\\t77221\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142947',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '-10',\n", - " '7885011',\n", - " '608892',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900111',\n", - " '-70010792700',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817983',\n", - " '2944657',\n", - " '-37.93',\n", - " '30342',\n", - " '31741',\n", - " '-770',\n", - " '-10',\n", - " ' 0',\n", - " '-10',\n", - " '30800',\n", - " '24640',\n", - " '77221',\n", - " '410']}}\n", - "{'arguments': [{'string_value': '005930'},\n", - " {'string_value': '주식체결'},\n", - " {'string_value': '142947\\t-77000\\t-500\\t-0.65\\t-77100\\t-77000\\t'\n", - " '-1\\t7885012\\t608892\\t+77600\\t+77800\\t-76600\\t'\n", - " '5\\t-900110\\t-70010715700\\t-89.75\\t0.13\\t201\\t'\n", - " '61.12\\t4596733\\t2\\t0\\t-89.69\\t000000\\t000000\\t'\n", - " '11814\\t090003\\t100015\\t133453\\t4817984\\t'\n", - " '2944657\\t-37.93\\t30343\\t31741\\t-77\\t-1\\t 0\\t'\n", - " '-1\\t30800\\t24640\\t77221\\t410'}],\n", - " 'name': 'OnReceiveRealData',\n", - " 'single_data': {'names': ['체결시간',\n", - " '현재가',\n", - " '전일대비',\n", - " '등락율',\n", - " '매도호가',\n", - " '매수호가',\n", - " '거래량',\n", - " '누적거래량',\n", - " '누적거래대금',\n", - " '시가',\n", - " '고가',\n", - " '저가',\n", - " '전일대비기호',\n", - " '거래량전일대비',\n", - " '거래대금증감',\n", - " '전일거래량대비율',\n", - " '거래회전율',\n", - " '거래비용',\n", - " '체결강도',\n", - " '시가총액',\n", - " '장구분',\n", - " 'KO접근도',\n", - " '822',\n", - " '567',\n", - " '568',\n", - " '851',\n", - " '1890',\n", - " '1891',\n", - " '1892',\n", - " '1030',\n", - " '1031',\n", - " '1032',\n", - " '1071',\n", - " '1072',\n", - " '1313',\n", - " '1315',\n", - " '1316',\n", - " '1314',\n", - " '1497',\n", - " '1498',\n", - " '620',\n", - " '732'],\n", - " 'values': ['142947',\n", - " '-77000',\n", - " '-500',\n", - " '-0.65',\n", - " '-77100',\n", - " '-77000',\n", - " '-1',\n", - " '7885012',\n", - " '608892',\n", - " '+77600',\n", - " '+77800',\n", - " '-76600',\n", - " '5',\n", - " '-900110',\n", - " '-70010715700',\n", - " '-89.75',\n", - " '0.13',\n", - " '201',\n", - " '61.12',\n", - " '4596733',\n", - " '2',\n", - " '0',\n", - " '-89.69',\n", - " '000000',\n", - " '000000',\n", - " '11814',\n", - " '090003',\n", - " '100015',\n", - " '133453',\n", - " '4817984',\n", - " '2944657',\n", - " '-37.93',\n", - " '30343',\n", - " '31741',\n", - " '-77',\n", - " '-1',\n", - " ' 0',\n", - " '-1',\n", - " '30800',\n", - " '24640',\n", - " '77221',\n", - " '410']}}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-01-18 14:29:53,341 [INFO] Stop listening realtime events... - :4\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "<_MultiThreadedRendezvous of RPC that terminated with:\n", - "\tstatus = StatusCode.CANCELLED\n", - "\tdetails = \"Locally cancelled by application!\"\n", - "\tdebug_error_string = \"None\"\n", - ">\n" - ] - } - ], - "source": [ - "import grpc\n", - "\n", - "try:\n", - " for i, event in enumerate(stream):\n", - " if i < 10:\n", - " pprint_event(event) # 노트북 출력이 너무 길어질 수 있어 최초 10개만 출력\n", - "except grpc.RpcError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/genindex.html b/genindex.html new file mode 100644 index 00000000..0d26aa76 --- /dev/null +++ b/genindex.html @@ -0,0 +1,6124 @@ + + + + + + + + Index — KOAPY 0.8.3 documentation + + + + + + + + + + + + + +
+ + +
+
+ + +
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | Y + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

K

+ + + +
    +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions + +
  • +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler + +
  • +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget + +
  • +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin + +
  • +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector + +
  • +
  • + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature + +
  • +
  • + koapy.backtrader + +
  • +
  • + koapy.backtrader.KiwoomOpenApiPlusBroker + +
  • +
  • + koapy.backtrader.KiwoomOpenApiPlusData + +
  • +
  • + koapy.backtrader.KiwoomOpenApiPlusEventStreamer + +
  • +
  • + koapy.backtrader.KiwoomOpenApiPlusStore + +
  • +
  • + koapy.backtrader.KrxHistoricalDailyPriceData + +
  • +
  • + koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite + +
  • +
  • + koapy.backtrader.KrxTradingCalendar + +
  • +
  • + koapy.backtrader.SQLAlchemyData + +
  • +
  • + koapy.backtrader.SQLAlchemySQLiteData + +
  • +
  • + koapy.backtrader.SQLiteData + +
  • +
  • + koapy.cli + +
  • +
  • + koapy.cli.__main__ + +
  • +
  • + koapy.cli.commands + +
  • +
  • + koapy.cli.commands.disable + +
  • +
  • + koapy.cli.commands.disable.auto_login + +
  • +
  • + koapy.cli.commands.enable + +
  • +
  • + koapy.cli.commands.enable.auto_login + +
  • +
  • + koapy.cli.commands.generate + +
  • +
  • + koapy.cli.commands.generate.grpc + +
  • +
  • + koapy.cli.commands.generate.grpc.ssl_credentials + +
  • +
  • + koapy.cli.commands.generate.openapi + +
  • +
  • + koapy.cli.commands.generate.openapi.python_stubs + +
  • +
  • + koapy.cli.commands.get + +
  • +
  • + koapy.cli.commands.get.account_data + +
  • +
  • + koapy.cli.commands.get.account_data.deposit + +
  • +
  • + koapy.cli.commands.get.account_data.evaluation + +
  • +
  • + koapy.cli.commands.get.account_data.orders + +
  • +
  • + koapy.cli.commands.get.account_data.userinfo + +
  • +
  • + koapy.cli.commands.get.chart_data + +
  • +
  • + koapy.cli.commands.get.chart_data.daily + +
  • +
  • + koapy.cli.commands.get.chart_data.minute + +
  • +
  • + koapy.cli.commands.get.openapi_meta + +
  • +
  • + koapy.cli.commands.get.openapi_meta.errmsg + +
  • +
  • + koapy.cli.commands.get.openapi_meta.modulepath + +
  • +
  • + koapy.cli.commands.get.openapi_meta.realinfo + +
  • +
  • + koapy.cli.commands.get.openapi_meta.trinfo + +
  • +
  • + koapy.cli.commands.get.stock_meta + +
  • +
  • + koapy.cli.commands.get.stock_meta.codelist + +
  • +
  • + koapy.cli.commands.get.stock_meta.codelist_interactive + +
  • +
  • + koapy.cli.commands.get.stock_meta.stockcode + +
  • +
  • + koapy.cli.commands.get.stock_meta.stockinfo + +
  • +
  • + koapy.cli.commands.get.stock_meta.stockname + +
  • +
  • + koapy.cli.commands.install + +
  • +
  • + koapy.cli.commands.install.openapi + +
  • +
  • + koapy.cli.commands.install.pywin32 + +
  • +
  • + koapy.cli.commands.serve + +
  • +
  • + koapy.cli.commands.show + +
  • +
  • + koapy.cli.commands.show.account_window + +
  • +
  • + koapy.cli.commands.uninstall + +
  • +
  • + koapy.cli.commands.uninstall.openapi + +
  • +
  • + koapy.cli.commands.uninstall.pywin32 + +
  • +
  • + koapy.cli.commands.update + +
  • +
  • + koapy.cli.extensions + +
  • +
  • + koapy.cli.extensions.functools + +
  • +
  • + koapy.cli.extensions.parser + +
  • +
  • + koapy.cli.extensions.verbose_option + +
  • +
  • + koapy.cli.utils + +
  • +
  • + koapy.cli.utils.credentials + +
  • +
  • + koapy.cli.utils.fail_with_usage + +
  • +
  • + koapy.cli.utils.grpc_options + +
  • +
  • + koapy.cli.utils.openapi + +
  • +
  • + koapy.cli.utils.pywin32 + +
  • +
  • + koapy.cli.utils.verbose_option + +
  • +
  • + koapy.compat + +
  • +
  • + koapy.compat.pyside2 + +
  • +
  • + koapy.compat.pyside2.QtAxContainer + +
  • +
  • + koapy.compat.pyside2.QtCore + +
  • +
  • + koapy.compat.pyside2.QtGui + +
  • +
  • + koapy.compat.pyside2.QtNetwork + +
  • +
  • + koapy.compat.pyside2.QtWidgets + +
  • +
  • + koapy.compat.pywinauto + +
  • +
  • + koapy.compat.pywinauto.findwindows + +
  • +
  • + koapy.compat.pywinauto.importlib + +
  • +
  • + koapy.compat.pywinauto.timings + +
  • +
  • + koapy.config + +
  • +
  • + koapy.utils + +
  • +
  • + koapy.utils.builtin + +
  • +
  • + koapy.utils.ctypes + +
  • +
  • + koapy.utils.data + +
  • +
  • + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader + +
  • +
  • + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader + +
  • +
  • + koapy.utils.data.KrxHistoricalDailyPriceDataLoader + +
  • +
  • + koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader + +
  • +
  • + koapy.utils.datetime + +
  • +
  • + koapy.utils.exchange_calendars + +
  • +
  • + koapy.utils.grpc + +
  • +
  • + koapy.utils.itertools + +
  • +
  • + koapy.utils.logging + +
  • +
  • + koapy.utils.logging.Logging + +
  • +
  • + koapy.utils.logging.pyside2 + +
  • +
  • + koapy.utils.logging.pyside2.QAbstractSocketLogging + +
  • +
  • + koapy.utils.logging.pyside2.QObjectLogging + +
  • +
  • + koapy.utils.logging.pyside2.QThreadLogging + +
  • +
  • + koapy.utils.logging.pyside2.QWidgetLogging + +
  • +
  • + koapy.utils.logging.tqdm + +
  • +
  • + koapy.utils.logging.tqdm.TqdmStreamHandler + +
  • +
  • + koapy.utils.messaging + +
  • +
  • + koapy.utils.messaging.DiscordMessenger + +
  • +
  • + koapy.utils.messaging.Messenger + +
  • +
  • + koapy.utils.networking + +
  • +
  • + koapy.utils.notimplemented + +
  • +
  • + koapy.utils.platform + +
  • +
  • + koapy.utils.pywin32 + +
  • +
  • + koapy.utils.rate_limiting + +
  • +
  • + koapy.utils.rate_limiting.pyside2 + +
  • +
  • + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor + +
  • +
  • + koapy.utils.rate_limiting.RateLimiter + +
  • +
  • + koapy.utils.recursion + +
  • +
  • + koapy.utils.serialization + +
  • +
  • + koapy.utils.store + +
  • +
  • + koapy.utils.store.misc + +
  • +
  • + koapy.utils.store.misc.VersionedItem + +
  • +
  • + koapy.utils.store.sqlalchemy + +
  • +
  • + koapy.utils.store.sqlalchemy.Base + +
  • +
  • + koapy.utils.store.sqlalchemy.Library + +
  • +
  • + koapy.utils.store.sqlalchemy.Session + +
  • +
  • + koapy.utils.store.sqlalchemy.Snapshot + +
  • +
  • + koapy.utils.store.sqlalchemy.SnapshotAssociation + +
  • +
  • + koapy.utils.store.sqlalchemy.Symbol + +
  • +
  • + koapy.utils.store.sqlalchemy.Timestamp + +
  • +
  • + koapy.utils.store.sqlalchemy.Version + +
  • +
  • + koapy.utils.store.SQLiteFileLibrary + +
  • +
  • + koapy.utils.store.SQLiteStore + +
  • +
  • + koapy.utils.store.SQLiteStoreLibrary + +
  • +
  • + koapy.utils.subprocess + +
  • +
  • + koapy.utils.threading + +
  • +
  • KrxHistoricalDailyPriceData (class in koapy.backtrader.KrxHistoricalDailyPriceData) +
  • +
  • KrxHistoricalDailyPriceDataDownloader (class in koapy.utils.data) + +
  • +
  • KrxHistoricalDailyPriceDataForBacktestLoader (class in koapy.utils.data) + +
  • +
  • KrxHistoricalDailyPriceDataFromSQLite (class in koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite) +
  • +
  • KrxHistoricalDailyPriceDataLoader (class in koapy.utils.data) + +
  • +
  • KrxTradingCalendar (class in koapy.backtrader.KrxTradingCalendar) +
  • +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Y

+ + +
+ + + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/history.html b/history.html new file mode 100644 index 00000000..46936924 --- /dev/null +++ b/history.html @@ -0,0 +1,159 @@ + + + + + + + + + History — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

History

+
+

0.7.1 (2022-02-07)

+
    +
  • Latest release on PyPI.

  • +
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..107e57a9 --- /dev/null +++ b/index.html @@ -0,0 +1,213 @@ + + + + + + + + + Welcome to KOAPY’s documentation! — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + +
+ + + +
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/installation.html b/installation.html new file mode 100644 index 00000000..8ccba291 --- /dev/null +++ b/installation.html @@ -0,0 +1,300 @@ + + + + + + + + + Installation — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Installation

+
+

Stable release

+

KOAPY 를 설치하기 위해서는 아래 커맨드를 터미널에서 실행합니다:

+
$ pip install koapy
+
+
+

이 방법은 가장 최신의 안정적인 릴리즈 버전을 설치하기 때문에 추천하는 설치 방법 중 하나입니다.

+

만약에 pip 가 설치되어 있지 않다면, Python installation guide 를 참고하세요.

+
+
+

From sources

+

KOAPY 의 소스코드는 Github repo 에서 다운로드 받을 수 있습니다.

+

일반적으로 레포지토리를 클론하거나:

+
$ git clone git://github.com/elbakramer/koapy
+
+
+

아니면 tarball 을 다운로드 받으세요:

+
$ curl -OJL https://github.com/elbakramer/koapy/tarball/master
+
+
+

소스코드 사본을 확보했다면, 아래 명령어를 통해 설치할 수 있습니다:

+
$ pip install .
+
+
+
+
+

Environment

+

KOAPY 라이브러리 설치 이전의 환경 구성부터 최종 라이브러리 설치까지의 전체 과정에 대해 설명합니다.

+
+

OS

+

Windows 10 64bit 환경을 권장합니다.

+

비록 라이브러리가 32bit 환경을 강제하지만 그렇다고 굳이 OS 까지 32bit 를 사용할 필요는 없습니다.

+
+
+

Kiwoom Open API

+

키움증권의 계좌개설 및 HTS ID 연결까지는 진행되어 있는 것을 가정합니다.

+

이후 키움 OpenAPI+ 페이지를 방문해서 사용절차의 Step 1 부터 Step 4 까지 순서대로 따라 진행합니다. +물론 Step 3 의 “OCX 탑재 프로그램 제작” 은 이후 KOAPY 를 활용해서 제작할 수 있는 부분이니 +당장은 제공되는 자료들을 참고만 하는 수준이면 됩니다.

+

마지막 Step 4 의 상시 모의투자는 개발 과정에서 테스트 및 디버깅을 위해 필수로 신청합니다. +아니면 실제 서버에 대해서 요청을 할 수 밖에 없는데, 여러분의 자산은 소중합니다.

+
+
+

Python (Anaconda)

+

Python 을 설치하는데 여러 방법이 있겠지만, 여기서는 Anaconda distribution 을 설치하는 내용을 다룹니다.

+

글을 쓰는 현재 최신 Python 버전은 3.9 까지 나왔지만, Ananconda 에서 제공하는 기본 최신 버전은 3.8 이기 때문에 해당 버전을 기준으로 설명합니다.

+

Anaconda Products 페이지를 방문해서 하단으로 스크롤을 하면 Anaconda Installers 라고 해서 설치 파일들을 다운로드 할 수 있도록 되어있습니다. +여기서 Windows 하단의 “64-Bit Graphical Installer” 를 다운로드 해 설치합니다. +설치 시에 그냥 바로 32-Bit Python 을 설치하는 옵션도 있지만.. 개인적으로 권장하진 않습니다. +여기서는 64-Bit Anaconda 를 먼저 설치 후 conda env 를 통해 32-Bit 가상환경을 추가로 구성합니다.

+

설치가 완료되었으면 시작 화면의 검색창에 Anaconda 를 검색하는 경우 Anaconda Prompt (Anaconda3) 프로그램을 찾을 수 있습니다. +실행하면 검은색 프롬프트가 뜨는데, 여기서 python, conda 등의 명령어를 사용할 수 있습니다. +python 명령을 입력해 제대로 동작하는지 테스트해봅시다. 이후 문제가 없으면 exit() 를 입력해 Python 인터프리터에서 빠져나옵니다.

+
$ python
+Python 3.8.3 (default, Jul  2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
+Type "help", "copyright", "credits" or "license" for more information.
+>>> exit()
+
+
+

혹시나 pyreadline 혹은 history 관련 경고가 출력되는 경우에 아래 명령을 통해 패치된 버전으로 교체합니다.

+
$ pip install -I git+https://github.com/elbakramer/pyreadline.git
+
+
+

이제 32-Bit Python 을 설치할 차례입니다. +아래 명령을 한 줄씩 앞서 띄워놓은 프롬프트에 입력해 수행합니다.

+
$ set CONDA_FORCE_32BIT=1
+$ conda create -n x86 python=3.8 anaconda
+
+
+

여기서 -n 뒤에 오는 x86 값은 굳이 예시와 같지 않아도 됩니다. +이후에 32-Bit 환경이 필요할 때마다 환경을 불러오는 데에 키값으로 활용될 값입니다. +추후 여러 번 사용하면서 알아보기에/입력하기에 편할법한 값으로 대체하셔도 문제없습니다.

+

동의를 구하는 단계에서는 y 를 입력해줍니다.

+
...
+Proceed ([y]/n)? y
+...
+
+
+

설치가 완료되었으면 이제 아래 명령을 통해 32-Bit Python 환경을 불러옵니다.

+
$ conda activate x86
+
+
+

제대로 불러온 경우라면 입력창 앞의 괄호로 있던 (base) 가 (x86) 으로 대체될 겁니다. +앞서 64-Bit 에서 테스트했던 것과 똑같이 32-Bit 에 대해서도 문제가 없는지 확인해봅니다.

+
(x86) $ python
+Python 3.8.3 (default, Jul  2 2020, 17:28:51) [MSC v.1916 32 bit (Intel)] :: Anaconda, Inc. on win32
+Type "help", "copyright", "credits" or "license" for more information.
+>>> exit()
+
+
+

32-Bit Python 의 설치가 완료되었습니다. [MSC v.1916 32 bit (Intel)] 구문이 출력되는 것으로 32-Bit 환경이라는 것을 다시 한번 확인 가능합니다.

+

32-Bit 환경에서 다시 이전의 64-Bit (base) 환경으로 다시 돌아가고 싶은 경우에는 아래의 명령을 실행합니다.

+
(x86) $ conda deactivate
+
+
+

그러면 다시 앞의 (x86) 이 (base) 로 바뀌면서 64-Bit 환경으로 돌아오게 됩니다.

+

이제 다음부터는 Anaconda Prompt (Anaconda3) 실행 후 conda activate x86 을 통해서 32-Bit 환경을 불러오거나, +아니면 시작 화면에서 Anaconda Prompt (x86) 을 찾아서 실행하면 바로 32-Bit 환경으로 시작합니다.

+
+
+

KOAPY

+

이후 KOAPY 설치는 pip 를 통해 설치하면 됩니다:

+
$ pip install koapy
+
+
+

맨 위의 Stable release 의 내용과 동일한 내용입니다.

+

OpenAPI 와의 통신을 위해서 32-Bit 환경에는 필수로 설치되어야 합니다. +OpenAPI 의 OCX 라이브러리가 32-Bit 환경만 지원하기 때문입니다.

+

64-Bit 환경에서의 설치는 선택사항입니다. +혹시나 64-Bit 환경에서만 지원되는 라이브러리 및 기능을 트레이딩 로직에 접목시키고자 하는 경우, +32-Bit 환경에는 서버만 띄워두고 64Bit 환경에서 gRPC 클라이언트 API 를 통해 서버에 연결하여 동일하게 OpenAPI 의 모든 기능을 활용할 수 있습니다.

+

이후 사용법에 대해서는 Usage 를 참고하세요.

+
+
+

KOAPY CLI 를 활용한 OpenAPI 설치, 업데이트, 삭제

+

각각 아래의 명령어를 활용해 OpenAPI 를 설치, 업데이트, 삭제 할 수도 있습니다.

+
$ koapy install openapi    # OpenAPI 설치
+$ koapy update openapi     # OpenAPI 자동 버전 업데이트
+$ koapy uninstall openapi  # OpenAPI 삭제
+
+
+

설치, 삭제의 경우에는 임시폴더에 설치파일을 다운로드 받아 실행하여 설치, 삭제를 진행합니다. +업데이트의 경우에는 OpenAPI 의 버전 업데이트 기능을 활용하는데, 여기에는 로그인 처리를 위한 계정 정보 및 관리자 권한이 필요합니다.

+

각 명령어의 자세한 옵션등에 대해서는 -h 옵션을 통한 도움말을 확인하세요.

+
+
+

DLL 로딩 오류 해결방법 (KOAPY CLI 를 활용한 pywin32 설치)

+

의존성중에 pywin32 의 버전이 301 로 업데이트 되면서 특정 환경에서 (특히 conda 기반 환경) DLL 로딩 관련 오류가 발생할 수 있습니다. +기존에 conda 배포판에서 설치되어 있는 버전과 충돌이 나서 발생하는 이슈이기 때문에 문제가 되는 기존 설치를 제거해주어야 합니다.

+

대략 아래에 위치한 파일들이 문제를 일으킬 수 있습니다. 파일 이름에서 3X 값은 사용하는 Python 버전에 따라 달라질 수 있다는 뜻입니다.

+
${sys.prefix}/Library/bin/pythoncom3X.dll
+${sys.prefix}/Library/bin/pywintypes3X.dll
+${sys.prefix}/Lib/site-packages/win32/pythoncom3X.dll
+${sys.prefix}/Lib/site-packages/win32/pywintypes3X.dll
+
+
+

아니면 좀 더 쉽게 각각 아래의 명령어를 통해 pywin32 를 정상적으로 설치, 삭제 할 수 있습니다.

+
$ koapy install pywin32    # pywin32 설치
+$ koapy uninstall pywin32  # pywin32 삭제
+
+
+

실행시 일반적인 pip 를 통한 설치/삭제를 진행하고 이후 추가적인 후처리 스크립트를 수행해 정상적인 설치/삭제가 될 수 있도록 합니다.

+

각 명령어의 자세한 옵션등에 대해서는 -h 옵션을 통한 도움말을 확인하세요.

+
+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/koapy/__init__.py b/koapy/__init__.py deleted file mode 100644 index 3513340e..00000000 --- a/koapy/__init__.py +++ /dev/null @@ -1,120 +0,0 @@ -"""Top-level package for KOAPY.""" - -__author__ = """Yunseong Hwang""" -__email__ = "kika1492@gmail.com" -__version__ = "0.9.0" - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint import ( - CybosPlusEntrypoint, - ) - from koapy.backend.daishin_cybos_plus.core.CybosPlusError import ( - CybosPlusError, - CybosPlusRequestError, - ) - from koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy import ( - CybosPlusEntrypointProxy, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusBooleanReturnCodeError, - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( - KiwoomOpenApiPlusQAxWidget, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager import ( - KiwoomOpenApiPlusScreenManager, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( - KiwoomOpenApiPlusVersionUpdater, - ) - from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication import ( - KiwoomOpenApiPlusManagerApplication, - ) - -__classes_to_export__ = { - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint": [ - "KiwoomOpenApiPlusEntrypoint" - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget": [ - "KiwoomOpenApiPlusQAxWidget" - ], - "koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication": [ - "KiwoomOpenApiPlusManagerApplication" - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError": [ - "KiwoomOpenApiPlusError", - "KiwoomOpenApiPlusNegativeReturnCodeError", - "KiwoomOpenApiPlusBooleanReturnCodeError", - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo": [ - "KiwoomOpenApiPlusTrInfo" - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType": [ - "KiwoomOpenApiPlusRealType" - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager": [ - "KiwoomOpenApiPlusScreenManager" - ], - "koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater": [ - "KiwoomOpenApiPlusVersionUpdater" - ], - "koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint": [ - "CybosPlusEntrypoint" - ], - "koapy.backend.daishin_cybos_plus.core.CybosPlusError": [ - "CybosPlusError", - "CybosPlusRequestError", - ], - "koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy": [ - "CybosPlusEntrypointProxy" - ], -} - -__module_for_each_class_to_export__ = { - name: module - for module in __classes_to_export__ - for name in __classes_to_export__[module] -} - -__all__ = [ - "KiwoomOpenApiPlusEntrypoint", - "KiwoomOpenApiPlusQAxWidget", - "KiwoomOpenApiPlusManagerApplication", - "KiwoomOpenApiPlusError", - "KiwoomOpenApiPlusNegativeReturnCodeError", - "KiwoomOpenApiPlusBooleanReturnCodeError", - "KiwoomOpenApiPlusTrInfo", - "KiwoomOpenApiPlusRealType", - "KiwoomOpenApiPlusScreenManager", - "KiwoomOpenApiPlusVersionUpdater", - "CybosPlusEntrypoint", - "CybosPlusError", - "CybosPlusRequestError", - "CybosPlusEntrypointProxy", -] - - -# lazily import classes on attribute access -# https://www.python.org/dev/peps/pep-0562/ -def __getattr__(name): - if name in __all__: - if name in __module_for_each_class_to_export__: - module_name = __module_for_each_class_to_export__[name] - import importlib - - module = importlib.import_module(module_name) - return getattr(module, name) - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/koapy/backend/__init__.py b/koapy/backend/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/__init__.py b/koapy/backend/daishin_cybos_plus/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/core/CybosPlusDispatch.py b/koapy/backend/daishin_cybos_plus/core/CybosPlusDispatch.py deleted file mode 100644 index 0c9bedb1..00000000 --- a/koapy/backend/daishin_cybos_plus/core/CybosPlusDispatch.py +++ /dev/null @@ -1,5 +0,0 @@ -from koapy.common import Dispatch - - -class CybosPlusDispatch(Dispatch): - pass diff --git a/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.py b/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.py deleted file mode 100644 index 8351b64f..00000000 --- a/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint.py +++ /dev/null @@ -1,18 +0,0 @@ -from koapy.backend.daishin_cybos_plus.core.CybosPlusDispatch import CybosPlusDispatch -from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin import ( - CybosPlusEntrypointMixin, -) -from koapy.utils.platform import is_32bit - - -class CybosPlusEntrypoint(CybosPlusEntrypointMixin): - - """ - http://cybosplus.github.io/ - """ - - def __init__(self): - assert is_32bit(), "Control object should be created in 32bit environment" - - def __getitem__(self, name): - return CybosPlusDispatch(name) diff --git a/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.py b/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.py deleted file mode 100644 index 99753226..00000000 --- a/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin.py +++ /dev/null @@ -1,565 +0,0 @@ -import datetime -import logging -import subprocess -import time - -import pandas as pd - -from koapy.backend.daishin_cybos_plus.core.CybosPlusTypeLibSpec import INSTALLATION_PATH -from koapy.backend.daishin_cybos_plus.stub import CpSysDib, CpUtil, DsCbo1 -from koapy.config import get_32bit_executable -from koapy.utils.ctypes import is_admin -from koapy.utils.itertools import chunk -from koapy.utils.logging.Logging import Logging -from koapy.utils.subprocess import function_to_subprocess_args - - -class CybosPlusEntrypointMixin(Logging): - def GetConnectState(self): - cybos: CpUtil.CpCybos = self["CpUtil.CpCybos"] - return cybos.IsConnect - - @classmethod - def ConnectUsingPywinauto_Impl(cls, credentials=None): - """ - 아래 구현을 참고해 작성함 - https://github.com/ippoeyeslhw/cppy/blob/master/cp_luncher.py - """ - - import pywinauto - - is_in_development = False - - if credentials is None: - from koapy.config import config - - credentials = config.get("koapy.backend.daishin_cybos_plus.credentials") - - userid = credentials.get("user_id") - password = credentials.get("user_password") - cert = credentials.get("cert_password") - - auto_account_password = credentials.get("auto_account_password") - auto_cert_password = credentials.get("auto_cert_password") - price_check_only = credentials.get("price_check_only") - - account_passwords = credentials.get("account_passwords") - - cls.logger.info("Starting CYBOS Starter application") - - app = pywinauto.Application(allow_magic_lookup=False) - desktop = pywinauto.Desktop(allow_magic_lookup=False) - - starter_path = INSTALLATION_PATH / "STARTER" / "ncStarter.exe" - starter_command = f"{starter_path} /prj:cp" - - app.start(starter_command) - - from koapy.utils.pywinauto import wait_any - - ask_stop = desktop.window(title="ncStarter") - starter = desktop.window(title="CYBOS Starter") - - def wait_ask_stop_ready(): - ask_stop.wait("ready", timeout=1) - return 0 - - def wait_starter_ready(): - starter.wait("ready", timeout=1) - return 1 - - cls.logger.info("Waiting for CYBOS Starter login screen") - try: - index = wait_any( - [ - wait_ask_stop_ready, - wait_starter_ready, - ], - timeout=30, - ) - except pywinauto.timings.TimeoutError: - cls.logger.exception("Failed to find login screen") - raise - else: - if index == 0: - cls.logger.info("Existing program found, shutting down") - if is_in_development: - ask_stop.print_control_identifiers() - if ask_stop["Static2"].window_text().endswith("종료하시겠습니까?"): - ask_stop["Button1"].click() - try: - cls.logger.info( - "Wating for possible failure message on shutdown" - ) - ask_stop.wait_not("ready", timeout=10) - except pywinauto.timings.TimeoutError as err: - cls.logger.error("Failed to shutdown existing program") - if is_in_development: - ask_stop.print_control_identifiers() - if ask_stop["Static2"].window_text().endswith("종료할 수 없습니다."): - ask_stop["Button"].click() - raise RuntimeError("Cannot stop existing program") from err - else: - cls.logger.info("Successfully shutdown existing program") - try: - starter.wait("ready", timeout=30) - except pywinauto.timings.TimeoutError: - cls.logger.exception("Failed to find login screen") - raise - else: - cls.logger.info("CYBOS Starter login screen found") - elif index == 1: - cls.logger.info("CYBOS Starter login screen found") - - if is_in_development: - starter.print_control_identifiers() - - if userid: - cls.logger.info("Putting user id") - starter["Edit1"].set_text(userid) - if password: - cls.logger.info("Putting user password") - starter["Edit2"].set_text(password) - else: - raise RuntimeError("No user password given") - - if not price_check_only: - if cert: - cls.logger.info("Putting cert password") - starter["Edit3"].set_text(cert) - else: - raise RuntimeError("No cert password given") - - if price_check_only: - if starter["Edit3"].is_enabled(): - cls.logger.info("Checking price check only option") - starter["Button6"].check_by_click() - else: - if not starter["Edit3"].is_enabled(): - starter["Button6"].uncheck_by_click() - - if auto_account_password: - cls.logger.info("Checking auto account password option") - starter["Button4"].check() # check dosen't work - try: - confirm = desktop.window(title="대신증권") - confirm.wait("ready", timeout=5) - except pywinauto.timings.TimeoutError: - pass - else: - if is_in_development: - confirm.print_control_identifiers() - confirm["Button"].click() - else: - starter["Button4"].uncheck() # uncheck dosen't work - - if auto_cert_password: - cls.logger.info("Checking auto cert password option") - starter["Button5"].check() # check dosen't work - try: - confirm = desktop.window(title="대신증권") - confirm.wait("ready", timeout=5) - except pywinauto.timings.TimeoutError: - pass - else: - if is_in_development: - confirm.print_control_identifiers() - confirm["Button"].click() - else: - starter["Button5"].uncheck() # uncheck dosen't work - - cls.logger.info("Clicking login button") - starter["Button1"].click() - - cls.logger.info("Setting account passwords if necessary") - should_stop = False - while not should_stop: - try: - cls.logger.info("Waiting for account password setting screen") - account_password = desktop.window(title="종합계좌 비밀번호 확인 입력") - account_password.wait("ready", timeout=5) - except pywinauto.timings.TimeoutError: - cls.logger.info("Account password setting screen not found") - should_stop = True - else: - cls.logger.info("Account password setting screen found") - if is_in_development: - account_password.print_control_identifiers() - account_no = ( - account_password["Static"].window_text().split(":")[-1].strip() - ) - if account_no in account_passwords: - account_password["Edit"].set_text(account_passwords[account_no]) - else: - raise RuntimeError( - "No account password given for account %s" % account_no - ) - account_password["Button1"].click() - - try: - cls.logger.info("Waiting for starter screen to be closed") - starter.wait_not("visible", timeout=60) - except pywinauto.timings.TimeoutError: - cls.logger.warning("Could not wait for starter screen to be closed") - else: - cls.logger.info("Starter screen is closed") - try: - cls.logger.info("Waiting for notice window") - notice = desktop.window(title="공지사항") - notice.wait("ready", timeout=60) - except pywinauto.timings.TimeoutError: - cls.logger.info("No notice window found") - else: - cls.logger.info("Closing notice window") - notice.close() - try: - cls.logger.info("Waiting for the notice window to be closed") - notice.wait_not("visible", timeout=60) - except pywinauto.timings.TimeoutError: - cls.logger.warning("Could not wait for notice screen to be closed") - else: - cls.logger.info("Notice window is closed") - - @classmethod - def ConnectUsingPywinauto_RunScriptInSubprocess(cls, credentials=None): - import json - - def main(): - import json - import sys - - from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint import ( - CybosPlusEntrypoint, - ) - - credentials = json.load(sys.stdin) - CybosPlusEntrypoint.ConnectUsingPywinauto_Impl(credentials) - - executable = get_32bit_executable() - args = function_to_subprocess_args(main, executable=executable) - return subprocess.run( - args, - input=json.dumps(credentials), - text=True, - check=True, - ) - - def ConnectUsingPywinauto(self, credentials=None): - return self.ConnectUsingPywinauto_RunScriptInSubprocess(credentials) - - def Connect(self, credentials=None): - assert is_admin(), "Connect() method requires to be run as administrator" - - self.ConnectUsingPywinauto(credentials) - - if self.GetConnectState() == 0: - self.logger.error("Failed to start and connect to CYBOS Plus") - else: - self.logger.info("Succesfully connected to CYBOS Plus") - - return self.GetConnectState() - - def CommConnect(self, credentials=None): - return self.Connect(credentials) - - def EnsureConnected(self, credentials=None): - errcode = 0 - if self.GetConnectState() == 0: - self.Connect(credentials) - if self.GetConnectState() == 0: - raise RuntimeError("CYBOS Plus is not running, please start CYBOS Plus") - return errcode - - def GetCodeListByMarketAsList(self, market): - """ - 0: 구분없음 - 1: 거래소 - 2: 코스닥 - 3: 프리보드 - 4: KRX - """ - codemgr: CpUtil.CpCodeMgr = self["CpUtil.CpCodeMgr"] - codes = codemgr.GetStockListByMarket(market) - codes = list(codes) - return codes - - def GetKospiCodeList(self): - codes = self.GetCodeListByMarketAsList(1) - return codes - - def GetKosdaqCodeList(self): - codes = self.GetCodeListByMarketAsList(2) - return codes - - def GetGeneralCodeList( - self, - include_preferred_stock=False, - include_etn=False, - include_etf=False, - include_mutual_fund=False, - include_reits=False, - include_kosdaq=False, - ): - - codes = self.GetCodeListByMarketAsList(1) - codemgr: CpUtil.CpCodeMgr = self["CpUtil.CpCodeMgr"] - - if not include_preferred_stock: - codes = [code for code in codes if code.endswith("0")] - if not include_etn: - codes = [code for code in codes if not code.startswith("Q")] - if not include_etf: - codes = [ - code - for code in codes - if codemgr.GetStockSectionKind(code) not in [10, 12] - ] - if not include_mutual_fund: - codes = [ - code for code in codes if codemgr.GetStockSectionKind(code) not in [2] - ] - if not include_reits: - codes = [ - code for code in codes if codemgr.GetStockSectionKind(code) not in [3] - ] - - if include_kosdaq: - codes += self.GetCodeListByMarketAsList(2) - - codes = sorted(codes) - - return codes - - def GetStockDataAsDataFrame( - self, - code, - chart_type, - interval, - start_date=None, - end_date=None, - adjusted_price=False, - adjustement_only=False, - ): - """ - http://cybosplus.github.io/cpsysdib_rtf_1_/stockchart.htm - """ - chart: CpSysDib.StockChart = self["CpSysDib.StockChart"] - cybos: CpUtil.CpCybos = self["CpUtil.CpCybos"] - - needs_time = chart_type in ["m", "T"] - - if len(code) == 6 and not code.startswith("A"): - code = "A" + code - - fids = [0] - - if needs_time: - fids += [1] - - if not adjustement_only: - fids += [2, 3, 4, 5, 8, 9] - else: - assert chart_type == "D" - adjusted_price = True - - if adjusted_price and chart_type == "D": - fids += [18, 19] - - sorted_fids = sorted(fids) - field_indexes = [sorted_fids.index(i) for i in fids] - - """ - maximum_value_count = 20000 - num_fis = len(fids) - expected_count = math.floor(maximum_value_count / num_fids) - 1 - request_count = expected_count + 1 - """ - - date_format_arg = "%Y%m%d%H%M%S" - date_format_input = "%Y%m%d" - - if start_date is not None: - if isinstance(start_date, str): - start_date_len = len(start_date) - if start_date_len == 14: - start_date = datetime.datetime.strptime(start_date, date_format_arg) - elif start_date_len == 8: - start_date = datetime.datetime.strptime( - start_date, date_format_input - ) - else: - raise ValueError - if not isinstance(start_date, datetime.datetime): - raise ValueError - start_date = int(start_date.strftime(date_format_input)) - else: - start_date = 0 - - if end_date is not None: - if isinstance(end_date, str): - end_date_len = len(end_date) - if end_date_len == 14: - end_date = datetime.datetime.strptime(end_date, date_format_arg) - elif end_date_len == 8: - end_date = datetime.datetime.strptime(end_date, date_format_input) - else: - raise ValueError - if not isinstance(end_date, datetime.datetime): - raise ValueError - else: - end_date = datetime.datetime.min - - end_date = int(end_date.strftime(date_format_input)) - - chart.SetInputValue(0, code) - chart.SetInputValue(1, ord("1")) - chart.SetInputValue(2, start_date) - chart.SetInputValue(3, end_date) - chart.SetInputValue(5, fids) - chart.SetInputValue(6, ord(chart_type)) - chart.SetInputValue(7, int(interval)) - chart.SetInputValue(9, ord("1") if adjusted_price else ord("0")) - - dataframes = [] - should_stop = False - - while not should_stop: - limit_remain_count = cybos.GetLimitRemainCount(1) - if limit_remain_count == 0: - limit_remain_time_millis = cybos.GetLimitRemainTime(1) - if limit_remain_time_millis > 0: - limit_remain_time_seconds = limit_remain_time_millis / 1000 - self.logger.debug( - "Sleeping for %f seconds", limit_remain_time_seconds - ) - time.sleep(limit_remain_time_seconds) - - chart.BlockRequest() - - records = [] - received_count = chart.GetHeaderValue(3) - - for i in range(received_count): - record = [chart.GetDataValue(j, i) for j in field_indexes] - records.append(record) - - names = chart.GetHeaderValue(2) - names = [names[i] for i in field_indexes] - - df = pd.DataFrame.from_records(records, columns=names) - - if df.shape[0] > 0 and self.logger.isEnabledFor(logging.DEBUG): - if needs_time: - dates = df["날짜"].astype(int).astype(str) - times = df["시간"].astype(int).astype(str).str.rjust(4, "0") - datetimes = dates.str.cat(times) - datetimes = pd.to_datetime(datetimes, format="%Y%m%d%H%M") - else: - dates = df["날짜"].astype(int).astype(str) - datetimes = dates - datetimes = pd.to_datetime(datetimes, format="%Y%m%d") - self.logger.debug( - "Received data from %s to %s for code %s", - datetimes.iloc[0], - datetimes.iloc[-1], - code, - ) - - should_stop = not chart.Continue - - dataframes.append(df) - - df = pd.concat(dataframes) - df.reset_index(drop=True, inplace=True) - - return df - - def GetDailyStockDataAsDataFrame( - self, code, start_date=None, end_date=None, adjusted_price=False - ): - return self.GetStockDataAsDataFrame( - code, "D", 1, start_date, end_date, adjusted_price=adjusted_price - ) - - def GetMinuteStockDataAsDataFrame( - self, code, interval, start_date=None, end_date=None, adjusted_price=False - ): - return self.GetStockDataAsDataFrame( - code, "m", interval, start_date, end_date, adjusted_price=adjusted_price - ) - - def GetDailyAdjustmentRatioAsDataFrame(self, code, start_date=None, end_date=None): - return self.GetStockDataAsDataFrame( - code, "D", 1, start_date, end_date, adjustement_only=True - ) - - def GetCurrentStockDataAsDataFrame(self, codes): - """ - http://cybosplus.github.io/cpdib_rtf_1_/stockmst2.htm - """ - stock: DsCbo1.StockMst2 = self["DsCbo1.StockMst2"] - cybos: CpUtil.CpCybos = self["CpUtil.CpCybos"] - - names = [ - "종목코드", - "종목명", - "시간", - "현재가", - "전일대비", - "상태구분", - "시가", - "고가", - "저가", - "매도호가", - "매수호가", - "거래량", - "거래대금", - "총매도잔량", - "총매수잔량", - "매도잔량", - "매수잔량", - "상장주식수", - "외국인보유비율", - "전일종가", - "전일거래량", - "체결강도", - "순간체결량", - "체결가비교", - "호가비교", - "동시호가구분", - "예상체결가", - "예상체결가 전일대비", - "예상체결가 상태구분", - "예상체결가 거래량", - ] - fids = list(range(len(names))) - - dataframes = [] - for code_chunk in chunk(codes, 110): - stock.SetInputValue(0, ",".join(code_chunk)) - - limit_remain_count = cybos.GetLimitRemainCount(1) - if limit_remain_count == 0: - limit_remain_time_millis = cybos.GetLimitRemainTime(1) - if limit_remain_time_millis > 0: - limit_remain_time_seconds = limit_remain_time_millis / 1000 - self.logger.debug( - "Sleeping for %f seconds", limit_remain_time_seconds - ) - time.sleep(limit_remain_time_seconds) - - stock.BlockRequest() - - received_count = stock.GetHeaderValue(0) - records = [] - for i in range(received_count): - record = [stock.GetDataValue(j, i) for j in fids] - records.append(record) - - df = pd.DataFrame.from_records(records, columns=names) - dataframes.append(df) - - df = pd.concat(dataframes) - df.reset_index(drop=True, inplace=True) - - return df diff --git a/koapy/backend/daishin_cybos_plus/core/CybosPlusError.py b/koapy/backend/daishin_cybos_plus/core/CybosPlusError.py deleted file mode 100644 index 80abdc87..00000000 --- a/koapy/backend/daishin_cybos_plus/core/CybosPlusError.py +++ /dev/null @@ -1,74 +0,0 @@ -from functools import wraps - - -class CybosPlusError(Exception): - - pass - - -class CybosPlusRequestError(CybosPlusError): - - """ - 아래 문서에서 [BlockRequest/Blockrequest2/Request의 리턴값] 내용 참조 - http://cybosplus.github.io/cputil_rtf_1_/cybosplus_interface.htm - """ - - ERROR_MESSAGE_BY_CODE = { - 0: "정상요청", - 1: "통신요청 실패", - 2: "주문확인창에서 취소", - 3: "그외의 내부 오류", - 4: "주문요청 제한 개수 초과", - } - - @classmethod - def get_error_message_by_code(cls, code, default=None): - return cls.ERROR_MESSAGE_BY_CODE.get(code, default) - - @classmethod - def check_code_or_raise(cls, code): - if code != 0: - raise cls(code) - return code - - @classmethod - def wrap_to_check_code_or_raise(cls, func): - @wraps(func) - def wrapper(*args, **kwargs): - return cls.check_code_or_raise(func(*args, **kwargs)) - - return wrapper - - @classmethod - def try_or_raise(cls, arg): - if isinstance(arg, int): - return cls.check_code_or_raise(arg) - elif callable(arg): - return cls.wrap_to_check_code_or_raise(arg) - else: - raise TypeError("Expected 'int' or 'callable' but %s found" % type(arg)) - - def __init__(self, code, message=None): - if message is None: - message = self.get_error_message_by_code(code) - - super().__init__(message) - - self._code = code - self._message = message - - def __str__(self): - return self._message - - def __repr__(self): - return "{}({!r}, {!r})".format( - self.__class__.__name__, self._code, self._message - ) - - @property - def code(self): - return self._code - - @property - def message(self): - return self._message diff --git a/koapy/backend/daishin_cybos_plus/core/CybosPlusTypeLibSpec.py b/koapy/backend/daishin_cybos_plus/core/CybosPlusTypeLibSpec.py deleted file mode 100644 index 95aecd8a..00000000 --- a/koapy/backend/daishin_cybos_plus/core/CybosPlusTypeLibSpec.py +++ /dev/null @@ -1,29 +0,0 @@ -from pathlib import Path - -from pywintypes import IID - -from koapy.utils.pywin32 import GetLatestTypelibSpec, GetTypelibSpecs - -CPFOREDIB_CLSID = IID("{ABA39D6F-5AF4-4D10-8389-031055C13A75}") -CPFORETRADE_CLSID = IID("{1E3BC2CB-4AC7-46BB-AF63-11DEA8628E3C}") - -CPSYSDIB_CLSID = IID("{9C31B76A-7189-49A3-9781-3C6DD6ED5AD3}") -CPTRADE_CLSID = IID("{1F7D5E5A-05AB-4236-B6F3-3D383B09203A}") - -CPUTIL_CLSID = IID("{2DA9C35C-FE59-4A32-A942-325EE8A6F659}") -DSCBO1_CLSID = IID("{859343F1-08FD-11D4-8231-00105A7C4F8C}") - -CPUTIL_TYPELIB_SPECS = GetTypelibSpecs(CPUTIL_CLSID) -CPUTIL_TYPELIB_SPEC = GetLatestTypelibSpec(CPUTIL_TYPELIB_SPECS) - -CPUTIL_TYPELIB_DLL_PATH = ( - CPUTIL_TYPELIB_SPEC and CPUTIL_TYPELIB_SPEC.dll and Path(CPUTIL_TYPELIB_SPEC.dll) -) - -INSTALLATION_PATH_FROM_DEFAULT_INSTALLATION = Path("C:\\DAISHIN") -INSTALLATION_PATH_FROM_TYPELIB_DLL = ( - CPUTIL_TYPELIB_DLL_PATH and CPUTIL_TYPELIB_DLL_PATH.parent.parent -) -INSTALLATION_PATH = ( - INSTALLATION_PATH_FROM_TYPELIB_DLL or INSTALLATION_PATH_FROM_DEFAULT_INSTALLATION -) diff --git a/koapy/backend/daishin_cybos_plus/core/__init__.py b/koapy/backend/daishin_cybos_plus/core/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxy.py b/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxy.py deleted file mode 100644 index 577dcfb9..00000000 --- a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxy.py +++ /dev/null @@ -1,229 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor -from queue import Queue -from typing import Any, Callable, Optional - -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec - -import grpc - -from koapy.backend.daishin_cybos_plus.stub import ( - CpForeDib, - CpForeTrade, - CpSysDib, - CpTrade, - CpUtil, - DsCbo1, -) -from koapy.common import DispatchProxyService_pb2, DispatchProxyService_pb2_grpc -from koapy.common.DispatchProxyServiceMessageUtils import AssignValue, ExtractValue -from koapy.common.EventInstance import EventInstance -from koapy.utils.logging.Logging import Logging - -P = ParamSpec("P") - -CLSIDToClassMap = { - str(getattr(mod, name).CLSID): getattr(mod, name) - for mod in [ - CpForeDib, - CpForeTrade, - CpSysDib, - CpTrade, - CpUtil, - DsCbo1, - ] - for name in dir(mod) - if hasattr(getattr(mod, name), "CLSID") -} - - -class CybosPlusDispatchProxyMethod: - def __init__(self, proxy, name): - self._proxy = proxy - self._name = name - - def __call__(self, *args, **kwargs): - return self._proxy._CallMethod(self._name, args) - - -class CybosPlusDispatchProxyEventInstance(EventInstance[P]): - def __init__(self, proxy, name): - super().__init__() - self._proxy = proxy - self._name = name - - self._future = None - - def connect(self, slot: Callable[P, Any]): - with self._lock: - if slot not in self._slots: - self._slots.append(slot) - - if len(self._slots) > 0 and self._future is None: - self._future, _ = self._proxy._ConnectEvent(self._name) - - def disconnect(self, slot: Optional[Callable[P, Any]] = None): - super().disconnect(slot) - - -class CybosPlusDispatchProxy(Logging): - def __init__( - self, - iid: str, - stub: DispatchProxyService_pb2_grpc.DispatchProxyServiceStub, - timeout: Optional[int] = None, - max_workers: Optional[int] = None, - ): - self._iid = iid - self._stub = stub - - self._timeout = timeout - self._max_workers = max_workers - - self._class = CLSIDToClassMap[self._iid] - - self._properties = [ - name - for name in dir(self._class) - if isinstance(getattr(self._class, name), property) - and not name.startswith("On") - ] - self._methods = [ - name - for name in dir(self._class) - if hasattr(getattr(self._class, name), "__call__") - ] - self._events = [ - name - for name in dir(self._class) - if isinstance(getattr(self._class, name), property) - and name.startswith("On") - ] - - self._method_instances = {} - self._event_instances = {} - - for method in self._methods: - self._method_instances[method] = CybosPlusDispatchProxyMethod(self, method) - - for event in self._events: - self._event_instances[event] = CybosPlusDispatchProxyEventInstance( - self, event - ) - - self._executor = ThreadPoolExecutor(max_workers=self._max_workers) - - def _GetAttr(self, name): - request = DispatchProxyService_pb2.GetAttrRequest() - request.iid = self._iid - request.name = name - should_stop = False - while not should_stop: - try: - response = self._stub.GetAttr(request, timeout=self._timeout) - except grpc.RpcError as error: - # error = typing.cast(grpc.Call, error) - # pylint: disable=no-member - if error.code() == grpc.StatusCode.DEADLINE_EXCEEDED: - self.logger.warning( - "getattr(self, %r) timed out, retrying...", name - ) - else: - raise - else: - should_stop = True - result = ExtractValue(response.value) - return result - - def _SetAttr(self, name, value): - request = DispatchProxyService_pb2.SetAttrRequest() - request.iid = self._iid - request.name = name - request.value = value - should_stop = False - while not should_stop: - try: - response = self._stub.SetAttr(request, timeout=self._timeout) - except grpc.RpcError as error: - # error = typing.cast(grpc.Call, error) - # pylint: disable=no-member - if error.code() == grpc.StatusCode.DEADLINE_EXCEEDED: - self.logger.warning( - "setattr(self, %r, %r) timed out, retrying...", name, value - ) - else: - raise - else: - should_stop = True - return response and None - - def _CallMethod(self, name, args): - request = DispatchProxyService_pb2.CallMethodRequest() - request.iid = self._iid - request.name = name - for arg in args: - AssignValue(request.arguments.add().value, arg) - should_stop = False - while not should_stop: - try: - response = self._stub.CallMethod(request, timeout=self._timeout) - except grpc.RpcError as error: - # error = typing.cast(grpc.Call, error) - # pylint: disable=no-member - if error.code() == grpc.StatusCode.DEADLINE_EXCEEDED: - self.logger.warning( - "Method call %s(%s) timed out, retrying...", - name, - ", ".join(map(repr, args)), - ) - else: - raise - else: - should_stop = True - result = ExtractValue(response.return_value) - return result - - def _ConnectEvent(self, name): - request = DispatchProxyService_pb2.ConnectEventRequest() - request.establish_request.iid = self._iid - request.establish_request.name = name - event_instance = self._event_instances[name] - request_queue = Queue() - sentinel = object() - request_iterator = iter(request_queue.get, sentinel) - request_queue.put(request) - - def put_sentinel(): - request_queue.put(sentinel) - - response_iterator = self._stub.ConnectEvent(request_iterator) - - def submit(): - for response in response_iterator: - args = [ExtractValue(arg.value) for arg in response.arguments] - event_instance(*args) - request = DispatchProxyService_pb2.ConnectEventRequest() - request.ack_request # pylint: disable=pointless-statement - request_queue.put(request) - - future = self._executor.submit(submit) - - return future, put_sentinel - - def __getattr__(self, name): - if name in self._properties: - return self._GetAttr(name) - elif name in self._method_instances: - return self._method_instances[name] - elif name in self._event_instances: - return self._event_instances[name] - else: - return super().__getattribute__(name) - - def __setattr__(self, name, value): - if "_properties" in self.__dict__ and name in self.__dict__["_properties"]: - self._SetAttr(name, value) - else: - super().__setattr__(name, value) diff --git a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyService.py b/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyService.py deleted file mode 100644 index a28e9694..00000000 --- a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyService.py +++ /dev/null @@ -1,57 +0,0 @@ -import sys - -from concurrent.futures import ThreadPoolExecutor - -import grpc -import pythoncom - -from koapy.backend.daishin_cybos_plus.proxy.CybosPlusDispatchProxyServiceServicer import ( - CybosPlusDispatchProxyServiceServicer, -) -from koapy.common import DispatchProxyService_pb2_grpc - - -class CybosPlusDispatchProxyService: - def __init__(self, host=None, port=None, max_workers=None): - if host is None: - host = "localhost" - if port is None: - port = 3031 - - if max_workers is None: - max_workers = None - - self._host = host - self._port = port - self._max_workers = max_workers - - self._address = self._host + ":" + str(self._port) - self._servicer = CybosPlusDispatchProxyServiceServicer() - - def initializer(): - flags = getattr(sys, "coinit_flags", pythoncom.COINIT_MULTITHREADED) - pythoncom.CoInitializeEx(flags) - - self._executor = ThreadPoolExecutor( - max_workers=self._max_workers, - initializer=initializer, - ) - - self._server = grpc.server(self._executor) - DispatchProxyService_pb2_grpc.add_DispatchProxyServiceServicer_to_server( - self._servicer, self._server - ) - self._server.add_insecure_port(self._address) - - def __getattr__(self, name): - return getattr(self._server, name) - - -def main(): - service = CybosPlusDispatchProxyService() - service.start() - service.wait_for_termination() - - -if __name__ == "__main__": - main() diff --git a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyServiceServicer.py b/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyServiceServicer.py deleted file mode 100644 index def49f33..00000000 --- a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusDispatchProxyServiceServicer.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Union - -from pywintypes import IID - -from koapy.backend.daishin_cybos_plus.core.CybosPlusDispatch import CybosPlusDispatch -from koapy.common.DispatchProxyServiceServicer import DispatchProxyServiceServicer - - -class CybosPlusDispatchProxyServiceServicer(DispatchProxyServiceServicer): - def _GetDispatch(self, iid: Union[IID, str]) -> CybosPlusDispatch: - return CybosPlusDispatch(iid) diff --git a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.py b/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.py deleted file mode 100644 index c30ba063..00000000 --- a/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy.py +++ /dev/null @@ -1,46 +0,0 @@ -from threading import RLock - -import grpc - -from koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin import ( - CybosPlusEntrypointMixin, -) -from koapy.backend.daishin_cybos_plus.proxy.CybosPlusDispatchProxy import ( - CybosPlusDispatchProxy, -) -from koapy.common import DispatchProxyService_pb2, DispatchProxyService_pb2_grpc - - -class CybosPlusEntrypointProxy(CybosPlusEntrypointMixin): - def __init__(self, host=None, port=None): - if host is None: - host = "localhost" - if port is None: - port = 3031 - - self._host = host - self._port = port - - self._address = self._host + ":" + str(self._port) - self._channel = grpc.insecure_channel(self._address) - self._stub = DispatchProxyService_pb2_grpc.DispatchProxyServiceStub( - self._channel - ) - - grpc.channel_ready_future(self._channel).result(timeout=5) - - self._lock = RLock() - self._dispatch_proxies = {} - - def __getitem__(self, name): - if name not in self._dispatch_proxies: - with self._lock: - if name not in self._dispatch_proxies: - request = DispatchProxyService_pb2.GetDispatchRequest() - request.iid = name - response = self._stub.GetDispatch(request) - iid = response.iid - proxy = CybosPlusDispatchProxy(iid, self._stub) - self._dispatch_proxies[name] = proxy - proxy = self._dispatch_proxies[name] - return proxy diff --git a/koapy/backend/daishin_cybos_plus/proxy/__init__.py b/koapy/backend/daishin_cybos_plus/proxy/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/stub/CpForeDib.py b/koapy/backend/daishin_cybos_plus/stub/CpForeDib.py deleted file mode 100644 index a54cf49b..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/CpForeDib.py +++ /dev/null @@ -1,179 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class IForeDib: - CLSID = IID("{366798F0-BAC3-4F67-AAB0-0DB7F9EF021C}") - - def Request(self) -> None: - ... - - def Subscribe(self) -> None: - ... - - def Unsubscribe(self) -> None: - ... - - def GetHeaderValue(self, _MIDL__IForeDib0000_: int) -> Any: - ... - - def GetDataValue(self, _MIDL__IForeDib0001_: int, _MIDL__IForeDib0002_: int) -> Any: - ... - - def GetInputValue(self, _MIDL__IForeDib0003_: int) -> Any: - ... - - def SetInputValue(self, _MIDL__IForeDib0004_: int, newVal: Any) -> None: - ... - - def GetDibStatus(self) -> int: - ... - - def GetDibMsg1(self) -> str: - ... - - def GetDibMsg2(self) -> str: - ... - - def BlockRequest(self) -> int: - ... - - def SubscribeLatest(self) -> None: - ... - - def BlockRequest2(self, BlockOption: int) -> int: - ... - - @property - def Header(self) -> Any: - ... - - @property - def Data(self) -> Any: - ... - - @property - def Input(self) -> Any: - ... - - @property - def Continue(self) -> int: - ... - - -class IForeDibEvents: - CLSID = IID("{505ECBD8-8FA3-4BFB-B577-2134CE46245E}") - - @property - def OnReceived(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class IForeDibEventsHandler: - CLSID = IID("{505ECBD8-8FA3-4BFB-B577-2134CE46245E}") - - def OnReceived(self) -> None: - ... - - -class ICpForeField: - CLSID = IID("{AB43E72A-E1FE-4EDE-B37A-3F75F1B3C026}") - - @property - def Name(self) -> str: - ... - - @property - def fid(self) -> int: - ... - - -class ICpForeFields: - CLSID = IID("{1A154454-862E-4EA9-BE59-D63216EE6EFE}") - - def __call__(self, Index: int) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpForeField(ICpForeField): - CLSID = IID("{93CEC1C0-47AE-474C-93BD-A952B67C5256}") - - -class CpForeFields(ICpForeFields): - CLSID = IID("{EF426FAC-8B2F-4D4E-883F-42ADCA3D258C}") - - -class OvFutMst(IForeDib, IForeDibEvents): - CLSID = IID("{60291C5F-0F0D-413F-A7E5-8FB699E8F050}") - PROGID = "CpForeDib.OvFutMst.1" - - -class OvFutCur(IForeDib, IForeDibEvents): - CLSID = IID("{10C45173-F22A-4037-AEF9-0A13BA3FA146}") - PROGID = "CpForeDib.OvFutCur.1" - - -class OvFutBid(IForeDib, IForeDibEvents): - CLSID = IID("{2117D620-501B-48F5-A6C0-2EA83A91453A}") - PROGID = "CpForeDib.OvFutBid.1" - - -class FxMgMst(IForeDib, IForeDibEvents): - CLSID = IID("{DFCAA3BE-2C51-4D22-8B40-8BD5A26987B9}") - PROGID = "CpForeDib.FxMgMst.1" - - -class FxMgCur(IForeDib, IForeDibEvents): - CLSID = IID("{1BA716D8-C71E-42B8-813D-F07BBDC08887}") - PROGID = "CpForeDib.FxMgCur.1" - - -class FxMgOrdReceive(IForeDib, IForeDibEvents): - CLSID = IID("{1BDD5625-B398-44EF-B81D-28F599E5F932}") - PROGID = "CpForeDib.FxMgOrdReceive.1" - - -class FxMgConclusion(IForeDib, IForeDibEvents): - CLSID = IID("{1593F7B5-6E9A-47D2-A121-0A370A363F64}") - PROGID = "CpForeDib.FxMgConclusion.1" - - -class FxMgBalance(IForeDib, IForeDibEvents): - CLSID = IID("{CDB1D9C6-C6DF-4004-8BB7-E6D282BBF938}") - PROGID = "CpForeDib.FxMgBalance.1" - - -class OvFutOrdReceive(IForeDib, IForeDibEvents): - CLSID = IID("{DF4AF880-ED67-4825-A61C-24D1E5D62BF1}") - PROGID = "CpForeDib.OvFutOrdReceive.1" - - -class OvFutConclusion(IForeDib, IForeDibEvents): - CLSID = IID("{F49DAF7B-8F8C-4EBA-A379-A7A8D7119152}") - PROGID = "CpForeDib.OvFutConclusion.1" - - -class OvFutBalance(IForeDib, IForeDibEvents): - CLSID = IID("{B5F48DBB-14A4-4346-966C-35187E1390B6}") - PROGID = "CpForeDib.OvFutBalance.1" - - -class OvFutureChart(IForeDib, IForeDibEvents): - CLSID = IID("{C5082D47-B750-4F6B-A71B-2FFF2BECEFB9}") - PROGID = "CpForeDib.OvFutureChart.1" - - -class FxMgChart(IForeDib, IForeDibEvents): - CLSID = IID("{13C7321A-77F2-46EA-8330-405553D0EB44}") - PROGID = "CpForeDib.FxMgChart.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/CpForeTrade.py b/koapy/backend/daishin_cybos_plus/stub/CpForeTrade.py deleted file mode 100644 index 5a335421..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/CpForeTrade.py +++ /dev/null @@ -1,194 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class ICpForeTdUtil: - CLSID = IID("{1427FCED-19F3-4433-90FC-15F92272F6A7}") - - def TradeInit(self, Reserved: int = 0) -> int: - ... - - def GoodsList(self, acc: str, Filter: int) -> Any: - ... - - @property - def AccountNumber(self) -> Any: - ... - - -class ICpTdField: - CLSID = IID("{9B522D78-88D9-4D5F-A4E0-16A936830F43}") - - @property - def Name(self) -> str: - ... - - @property - def fid(self) -> int: - ... - - -class ICpTdFields: - CLSID = IID("{75081DAF-290E-4036-B49D-9C45A990E96F}") - - def __call__(self, Index: int) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpTdField(ICpTdField): - CLSID = IID("{138DF993-B1BB-4E51-8C71-6248B9C010C4}") - - -class CpTdFields(ICpTdFields): - CLSID = IID("{8C150715-212A-453E-AC5A-1A1183B0A36F}") - - -class ICpForeTdDib: - CLSID = IID("{18F5F66F-7DC7-4394-B025-5B981C3838F5}") - - def GetHeaderValue(self, _MIDL__ICpForeTdDib0000_: int) -> Any: - ... - - def GetDataValue( - self, _MIDL__ICpForeTdDib0001_: int, _MIDL__ICpForeTdDib0002_: int - ) -> Any: - ... - - def GetInputValue(self, _MIDL__ICpForeTdDib0003_: int) -> Any: - ... - - def SetInputValue(self, _MIDL__ICpForeTdDib0004_: int, newVal: Any) -> None: - ... - - def GetDibStatus(self) -> int: - ... - - def GetDibMsg1(self) -> str: - ... - - def GetDibMsg2(self) -> str: - ... - - def BlockRequest(self) -> int: - ... - - def BlockRequest2(self, BlockOption: int) -> int: - ... - - def Request(self) -> int: - ... - - @property - def Header(self) -> Any: - ... - - @property - def Data(self) -> Any: - ... - - @property - def Input(self) -> Any: - ... - - @property - def Continue(self) -> int: - ... - - @Continue.setter - def Continue(self, Continue: int) -> None: - ... - - -class IForeTdDibEvents: - CLSID = IID("{EC430179-1510-4E67-96EA-376C4759E928}") - - @property - def OnReceived(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class IForeTdDibEventsHandler: - CLSID = IID("{EC430179-1510-4E67-96EA-376C4759E928}") - - def OnReceived(self) -> None: - ... - - -class CpForeTdUtil(ICpForeTdUtil): - CLSID = IID("{D99B83AA-06D4-4944-81BC-7B18C0FCC491}") - PROGID = "CpForeTrade.CpForeTdUtil.1" - - -class CpForeTradeKey(ICpForeTdDib): - CLSID = IID("{31A04D10-E36E-4571-A058-B5FFD650E269}") - - -class OvFutOrder(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{CF80E93D-C153-404F-8728-DE2B2C259B92}") - PROGID = "CpForeTrade.OvFutOrder.1" - - -class OvFutConInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{A03A1CC0-0DD3-4CB6-9DEB-5942013547C9}") - PROGID = "CpForeTrade.OvFutConInq.1" - - -class OvFutNotConInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{ECD09FE2-F364-40CE-84D4-0519789852E8}") - PROGID = "CpForeTrade.OvFutNotConInq.1" - - -class OvfNotPaymentInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{87C0CF3C-BD04-43C7-A769-258F6ECD4E95}") - PROGID = "CpForeTrade.OvfNotPaymentInq.1" - - -class OvfDepositRecInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{EA07EC46-90D7-4FDA-86AB-B9E18FE20B97}") - PROGID = "CpForeTrade.OvfDepositRecInq.1" - - -class FxMgOrder(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{EA025F0D-E04D-43E8-B2AD-FB136B7D871A}") - PROGID = "CpForeTrade.OvFutOrder.1" - - -class FxMgConInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{35BA0F1E-9483-4A7E-945C-2106D99B86F1}") - PROGID = "CpForeTrade.FxMgConInq.1" - - -class FxMgNotConInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{D78F80D3-7189-45B1-9D41-40323059E330}") - PROGID = "CpForeTrade.FxMgNotConInq.1" - - -class FxMgNotPaymentInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{46131954-6A5A-43B8-94B2-63056A75171C}") - PROGID = "CpForeTrade.FxMgNotPaymentInq.1" - - -class FxMgDepositRecInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{65210B9E-4F64-419A-AB4E-A41FD1202943}") - PROGID = "CpForeTrade.FxMgDepositRecInq.1" - - -class OvfOffDepositRecInq(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{1FF05E16-3C49-49F1-A8C9-A6AFB5E89162}") - PROGID = "CpForeTrade.OvfOffDepositRecInq.1" - - -class CpTd6345(ICpForeTdDib, IForeTdDibEvents): - CLSID = IID("{9DFA90BB-7BD9-4F2A-8777-34CB94781FBF}") - PROGID = "CpForeTrade.CpTd6345.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/CpSysDib.py b/koapy/backend/daishin_cybos_plus/stub/CpSysDib.py deleted file mode 100644 index 445d4d09..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/CpSysDib.py +++ /dev/null @@ -1,576 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class ISysDib: - CLSID = IID("{8146AC72-E93B-42A8-86A3-B9851AA15229}") - - def Request(self) -> None: - ... - - def Subscribe(self) -> None: - ... - - def Unsubscribe(self) -> None: - ... - - def GetHeaderValue(self, _MIDL__ISysDib0000_: int) -> Any: - ... - - def GetDataValue(self, _MIDL__ISysDib0001_: int, _MIDL__ISysDib0002_: int) -> Any: - ... - - def GetInputValue(self, _MIDL__ISysDib0003_: int) -> Any: - ... - - def SetInputValue(self, _MIDL__ISysDib0004_: int, newVal: Any) -> None: - ... - - def GetDibStatus(self) -> int: - ... - - def GetDibMsg1(self) -> str: - ... - - def GetDibMsg2(self) -> str: - ... - - def BlockRequest(self) -> int: - ... - - def SubscribeLatest(self) -> None: - ... - - def BlockRequest2(self, BlockOption: int) -> int: - ... - - @property - def Header(self) -> Any: - ... - - @property - def Data(self) -> Any: - ... - - @property - def Input(self) -> Any: - ... - - @property - def Continue(self) -> int: - ... - - -class ISysDibEvents: - CLSID = IID("{60D7702A-57BA-4869-AF3F-292FDC909D75}") - - @property - def OnReceived(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class ISysDibEventsHandler: - CLSID = IID("{60D7702A-57BA-4869-AF3F-292FDC909D75}") - - def OnReceived(self) -> None: - ... - - -class ICpField: - CLSID = IID("{C9FAC560-BE19-4FB2-801D-54F89D3FBC0A}") - - @property - def Name(self) -> str: - ... - - @property - def fid(self) -> int: - ... - - -class ICpFields: - CLSID = IID("{2A93E227-583D-427C-A430-2AB642C19E02}") - - def __call__(self, Index: int) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpField(ICpField): - CLSID = IID("{BF085D15-ACE9-4E36-8E48-76BB29DA5584}") - - -class CpFields(ICpFields): - CLSID = IID("{43733869-291F-43B0-B2EE-8019E7363B55}") - - -class ICpSys: - CLSID = IID("{4BE681C3-67B8-4B6A-BC98-89FF0DF4238E}") - - def CpUnlock(self, code1: int, code2: int) -> None: - ... - - -class CpSvrNew7224(ISysDib, ISysDibEvents): - CLSID = IID("{E8931FA7-2E91-416F-85B8-F80351FD5C24}") - PROGID = "CpSysDib.CpSvrNew7224.1" - - -class CpSvr3745(ISysDib, ISysDibEvents): - CLSID = IID("{AF38F980-ABC8-4C99-8B95-19A1CC39ACB7}") - PROGID = "CpSysDib.CpSvr3745.1" - - -class CpSvr7043(ISysDib, ISysDibEvents): - CLSID = IID("{EA332802-B845-4C3D-8C3A-BBF6D0B11B79}") - PROGID = "CpSysDib.CpSvr7043.1" - - -class CpSvr8548(ISysDib, ISysDibEvents): - CLSID = IID("{DB6CADF4-515A-4845-BE7B-ECA2D93DAB26}") - PROGID = "CpSysDib.CpSvr8548.1" - - -class CpSvrNew7221(ISysDib, ISysDibEvents): - CLSID = IID("{942C11D6-2DA7-4119-8D4F-493F0623C1B7}") - PROGID = "CpSysDib.CpSvrNew7221.1" - - -class CpSvrNew7221S(ISysDib, ISysDibEvents): - CLSID = IID("{8A0FAF47-A6A1-4518-B66A-61B7143C389C}") - PROGID = "CpSysDib.CpSvrNew7221S.1" - - -class CpSvrNew7216(ISysDib, ISysDibEvents): - CLSID = IID("{6B0B7CB1-03BC-44CB-8768-79FFC699B41A}") - PROGID = "CpSysDib.CpSvrNew7216.1" - - -class CpSvr8114(ISysDib, ISysDibEvents): - CLSID = IID("{8DB220EA-04E0-4272-9AED-6B1550F6DBAB}") - PROGID = "CpSysDib.CpSvr8114.1" - - -class CpSvr9842(ISysDib, ISysDibEvents): - CLSID = IID("{79A10F99-442F-472D-8088-816B25F85523}") - PROGID = "CpSysDib.CpSvr9842.1" - - -class CpSvr9842S(ISysDib, ISysDibEvents): - CLSID = IID("{C6CE0564-B055-46AA-A406-DF1AF0A549C2}") - PROGID = "CpSysDib.CpSvr9842S.1" - - -class CpMarketWatch(ISysDib, ISysDibEvents): - CLSID = IID("{9FA37D6D-1E16-442C-8EDD-A3E423E8FEA1}") - PROGID = "CpSysDib.CpMarketWatch.1" - - -class CpMarketWatchS(ISysDib, ISysDibEvents): - CLSID = IID("{D6633FD4-D339-4782-B337-2A6C9ED3CA47}") - PROGID = "CpSysDib.CpMarketWatchS.1" - - -class CpSvrNew7222(ISysDib, ISysDibEvents): - CLSID = IID("{13173568-9547-4910-B040-9168A5DC950C}") - PROGID = "CpSysDib.CpSvrNew7222.1" - - -class CpSvr7748(ISysDib, ISysDibEvents): - CLSID = IID("{AF9498CB-FFBC-45FA-A5B5-3BE5E48146E5}") - PROGID = "CpSysDib.CpSvr7748.1" - - -class ElwAll(ISysDib, ISysDibEvents): - CLSID = IID("{061DCC2D-02E9-4F42-9090-3EACF821480B}") - PROGID = "CpSysDib.ElwAll.1" - - -class Elw(ISysDib, ISysDibEvents): - CLSID = IID("{49EC4E41-32D5-4994-8B0C-BC7AAB238E6A}") - PROGID = "CpSysDib.Elw.1" - - -class ElwUnderCur(ISysDib, ISysDibEvents): - CLSID = IID("{AE0BD6DB-C9C5-403B-AF49-7B953B362112}") - PROGID = "CpSysDib.ElwUnderCur.1" - - -class ElwInvest(ISysDib, ISysDibEvents): - CLSID = IID("{51BEC419-2C7F-456F-AF83-4E1E9C1F7543}") - PROGID = "CpSysDib.ElwInvest.1" - - -class CpSvrNew7215A(ISysDib, ISysDibEvents): - CLSID = IID("{4E793A3C-DFD4-499A-93F6-B2CEC3DC151B}") - PROGID = "CpSysDib.CpSvrNew7215A.1" - - -class CpSvrNew7215B(ISysDib, ISysDibEvents): - CLSID = IID("{BE5F7180-7E74-4F44-8C67-700811BAD363}") - PROGID = "CpSysDib.CpSvrNew7215B.1" - - -class CpSvr7068(ISysDib, ISysDibEvents): - CLSID = IID("{10674C56-4ACC-4104-BC8D-42F855EBA17D}") - PROGID = "CpSysDib.CpSvr7068.1" - - -class CpSvr7063(ISysDib, ISysDibEvents): - CLSID = IID("{C8C73E26-6C02-46CB-B8B6-1600E5A86A6B}") - PROGID = "CpSysDib.CpSvr7063.1" - - -class ElwJpbid(ISysDib, ISysDibEvents): - CLSID = IID("{75CCA696-16F2-459D-9F73-9EE5B92D60B3}") - PROGID = "CpSysDib.ElwJpbid.1" - - -class ElwJpbid2(ISysDib, ISysDibEvents): - CLSID = IID("{DAAF202A-393E-4353-A4EA-092733536C64}") - PROGID = "CpSysDib.ElwJpbid2.1" - - -class CpSvr7066(ISysDib, ISysDibEvents): - CLSID = IID("{42A23EE1-5CB9-4F9F-8467-208ED8602665}") - PROGID = "CpSysDib.CpSvr7066.1" - - -class CpSvr7254(ISysDib, ISysDibEvents): - CLSID = IID("{1B54A2E7-8F72-4825-B109-7E2DD61D6C8E}") - PROGID = "CpSysDib.CpSvr7254.1" - - -class CpSvr3744(ISysDib, ISysDibEvents): - CLSID = IID("{923667A7-245E-44E2-AB39-CB224F5B913E}") - PROGID = "CpSysDib.CpSvr3744.1" - - -class StockAdj(ISysDib, ISysDibEvents): - CLSID = IID("{EF251164-0FC9-4582-A6EE-7C6A3B981111}") - PROGID = "CpSysDib.StockAdj.1" - - -class StockUniMst(ISysDib, ISysDibEvents): - CLSID = IID("{7E291B7A-D229-4741-A8C1-C33B0DBBF6FB}") - PROGID = "CpSysDib.StockUniMst.1" - - -class StockUniCur(ISysDib, ISysDibEvents): - CLSID = IID("{DC573A7F-3301-47CE-B2F2-F36A1E5500B7}") - PROGID = "CpSysDib.StockUniCur.1" - - -class StockUniJpBid(ISysDib, ISysDibEvents): - CLSID = IID("{B7CC7EE7-C619-4D27-8EA9-03C2B0370ED0}") - PROGID = "CpSysDib.StockUniJpBid.1" - - -class StockUniWeek(ISysDib, ISysDibEvents): - CLSID = IID("{348306A3-8692-4758-AE08-883CF96B0B4C}") - PROGID = "CpSysDib.StockUniWeek.1" - - -class StockUniBid(ISysDib, ISysDibEvents): - CLSID = IID("{1C6B4381-B00C-4529-ABA1-FF705BFA342F}") - PROGID = "CpSysDib.StockUniBid.1" - - -class OptionCurOnly(ISysDib, ISysDibEvents): - CLSID = IID("{928A6FAF-3874-42D6-BCB6-74D65F758B35}") - PROGID = "CpSysDib.OptionCurOnly.1" - - -class WorldCur(ISysDib, ISysDibEvents): - CLSID = IID("{3D49364D-18D9-49A8-9B9F-7C5471EB129B}") - PROGID = "CpSysDib.WorldCur.1" - - -class MarketEye(ISysDib, ISysDibEvents): - CLSID = IID("{D71F9B56-85A0-49F8-B102-19C223ACF298}") - PROGID = "CpSysDib.MarketEye.1" - - -class StockChart(ISysDib, ISysDibEvents): - CLSID = IID("{4F5E5E9A-5BEA-409F-9828-B66A70B4B51B}") - PROGID = "CpSysDib.StockChart.1" - - -class CpSvr7037(ISysDib, ISysDibEvents): - CLSID = IID("{1AAC83CC-FA40-485F-952F-FB5667392E4F}") - PROGID = "CpSysDib.CpSvr7037.1" - - -class K200Expect(ISysDib, ISysDibEvents): - CLSID = IID("{39DADC73-104A-4C23-AC9B-9875B35EA194}") - PROGID = "CpSysDib.K200Expect.1" - - -class FutOptChart(ISysDib, ISysDibEvents): - CLSID = IID("{5337FA2B-B02E-42DC-A5A1-12BC4F36B6DA}") - PROGID = "CpSysDib.FutOptChart.1" - - -class CpSvrNew7043(ISysDib, ISysDibEvents): - CLSID = IID("{BC2B7C0D-8481-4067-B1A4-5D7BDCA9DCBA}") - PROGID = "CpSysDib.CpSvrNew7043.1" - - -class CpSvrNew7212(ISysDib, ISysDibEvents): - CLSID = IID("{DC43995C-F264-4ECA-B88A-20B4FD238DAF}") - PROGID = "CpSysDib.CpSvrNew7212.1" - - -class CpSvr7726(ISysDib, ISysDibEvents): - CLSID = IID("{23DEEA4C-FCF5-49B6-B1A8-07EF1D6D4AD4}") - PROGID = "CpSysDib.CpSvr7726.1" - - -class CpFutOptTheoVal(ISysDib, ISysDibEvents): - CLSID = IID("{FFE900B3-D906-492B-9AA1-C9411371C108}") - PROGID = "CpSysDib.CpFutOptTheoVal.1" - - -class CpSvr7326(ISysDib, ISysDibEvents): - CLSID = IID("{D9A23D4E-624D-43E8-9FDA-F9174A073209}") - PROGID = "CpSysDib.CpSvr7326.1" - - -class StockOpenSb(ISysDib, ISysDibEvents): - CLSID = IID("{F1AE467A-86BE-4F77-8A5C-F23D4883E3A7}") - PROGID = "CpSysDib.StockOpenSb.1" - - -class CmeMst(ISysDib, ISysDibEvents): - CLSID = IID("{9B08D6BE-4DE0-4F6A-B32A-22C9F0B182F7}") - PROGID = "CpSysDib.CmeMst.1" - - -class CmeMo(ISysDib, ISysDibEvents): - CLSID = IID("{8195B34A-E25A-4174-A41E-3283BFD0CBD6}") - PROGID = "CpSysDib.CmeMo.1" - - -class CmeBid(ISysDib, ISysDibEvents): - CLSID = IID("{E7FBCAA1-E01F-4CD5-B215-DB77D3AF5448}") - PROGID = "CpSysDib.CmeBid.1" - - -class CmeDaily(ISysDib, ISysDibEvents): - CLSID = IID("{09832FA6-1662-4EE3-9F91-6C8CD66EB3B2}") - PROGID = "CpSysDib.CmeDaily.1" - - -class CmeBidOnly(ISysDib, ISysDibEvents): - CLSID = IID("{2ADC5BB3-40A2-450C-A503-51084AD15D99}") - PROGID = "CpSysDib.CmeBidOnly.1" - - -class CmeCurOnly(ISysDib, ISysDibEvents): - CLSID = IID("{75FDB7F9-6B05-49E7-B7BD-80DA111FF3D5}") - PROGID = "CpSysDib.CmeCurOnly.1" - - -class CmeCurr(ISysDib, ISysDibEvents): - CLSID = IID("{70C14953-D33B-454B-856F-9464B7D7BAB5}") - PROGID = "CpSysDib.CmeCurr.1" - - -class FutureJpBid(ISysDib, ISysDibEvents): - CLSID = IID("{D14D1214-71D0-4207-9780-6DAC389EAE85}") - PROGID = "CpSysDib.FutureJpBid.1" - - -class OptionJpBid(ISysDib, ISysDibEvents): - CLSID = IID("{6D4EC009-130A-4C74-98D2-42B020889449}") - PROGID = "CpSysDib.OptionJpBid.1" - - -class CWList(ISysDib, ISysDibEvents): - CLSID = IID("{EDD5DE53-96D2-4F1D-BA3D-C6DF75154066}") - PROGID = "CpSysDib.CWList.1" - - -class NStockMst(ISysDib, ISysDibEvents): - CLSID = IID("{D3825EE2-C49F-4756-890D-530CDAA25EC5}") - PROGID = "CpSysDib.NStockMst.1" - - -class NStockCur(ISysDib, ISysDibEvents): - CLSID = IID("{3014C34B-46C3-4440-B6F5-93997817047B}") - PROGID = "CpSysDib.NStockCur.1" - - -class BondMst(ISysDib, ISysDibEvents): - CLSID = IID("{A0B46FA8-216D-47EB-A5DC-C500ACCEEA1A}") - PROGID = "CpSysDib.BondMst.1" - - -class BondCur(ISysDib, ISysDibEvents): - CLSID = IID("{3618D98B-BE61-4A46-9A2B-C6B38ECD2A09}") - PROGID = "CpSysDib.BondCur.1" - - -class FOExpectCur(ISysDib, ISysDibEvents): - CLSID = IID("{55D92823-F6CD-49FC-A3A8-9B4FAE025175}") - PROGID = "CpSysDib.FOExpectCur.1" - - -class EurexBid(ISysDib, ISysDibEvents): - CLSID = IID("{A45C67C3-53B6-4740-92AF-A04338D9215B}") - PROGID = "CpSysDib.EurexBid.1" - - -class EurexDaily(ISysDib, ISysDibEvents): - CLSID = IID("{A0696F58-8C6B-4E3B-8F7B-9EB4CC094EBB}") - PROGID = "CpSysDib.EurexDaily.1" - - -class EurexCurOnly(ISysDib, ISysDibEvents): - CLSID = IID("{3626A621-23F1-409F-BDD0-5AE10FF924E0}") - PROGID = "CpSysDib.EurexCurOnly.1" - - -class EurexMst(ISysDib, ISysDibEvents): - CLSID = IID("{65950801-9C94-4756-A92A-B20F319CDE2E}") - PROGID = "CpSysDib.EurexMst.1" - - -class EurexJpbid(ISysDib, ISysDibEvents): - CLSID = IID("{D07D7BAC-7FDD-4AA1-9FEB-156EC5344B8E}") - PROGID = "CpSysDib.EurexJpbid.1" - - -class CpSvrNew7244S(ISysDib, ISysDibEvents): - CLSID = IID("{5B6B6338-5843-4D9F-87BB-5C5BB40C579D}") - PROGID = "CpSysDib.CpSvrNew7244S.1" - - -class CpSvrNew8300(ISysDib, ISysDibEvents): - CLSID = IID("{D03AB487-0553-4F48-8DAA-C7A8C1549B11}") - PROGID = "CpSysDib.CpSvrNew8300.1" - - -class CssStgList(ISysDib, ISysDibEvents): - CLSID = IID("{B9CB3A84-F66B-4FB0-A481-C9CCC8B8AE1F}") - PROGID = "CpSysDib.CssStgList.1" - - -class CssStgFind(ISysDib, ISysDibEvents): - CLSID = IID("{60E404D1-AA50-4AC9-BC86-476626CBC983}") - PROGID = "CpSysDib.CssStgFind.1" - - -class CssWatchStgControl(ISysDib, ISysDibEvents): - CLSID = IID("{6F6615F0-DA4A-4E5F-8E74-F3597F9D6865}") - PROGID = "CpSysDib.CssWatchStgControl.1" - - -class CssWatchStgSubscribe(ISysDib, ISysDibEvents): - CLSID = IID("{7F5AF5D2-2C13-4E84-92E4-9298F1436756}") - PROGID = "CpSysDib.CssWatchStgSubscribe.1" - - -class CssAlert(ISysDib, ISysDibEvents): - CLSID = IID("{37001E74-5FAA-4502-94FA-3AE9FC102DEB}") - PROGID = "CpSysDib.CssAlert.1" - - -class CpSvr7921(ISysDib, ISysDibEvents): - CLSID = IID("{435AC599-969D-46A0-B119-6D7C4C7F5AB7}") - PROGID = "CpSysDib.CpSvr7921.1" - - -class CpSvr8119S(ISysDib, ISysDibEvents): - CLSID = IID("{02762DC2-93FA-48CA-897C-DAE7D68514AB}") - PROGID = "CpSysDib.CpSvr8119S.1" - - -class CpSvr9619S(ISysDib, ISysDibEvents): - CLSID = IID("{772812D7-6F16-41C5-9E4A-95955F9203DC}") - PROGID = "CpSysDib.CpSvr9619S.1" - - -class CpSvr7033(ISysDib, ISysDibEvents): - CLSID = IID("{EF88BBDC-8403-41C7-9FA1-2E0B5D52FEB4}") - PROGID = "CpSysDib.CpSvr7033.1" - - -class CpSvr7034(ISysDib, ISysDibEvents): - CLSID = IID("{AAFD418D-0D1A-41C1-9E70-E91962002932}") - PROGID = "CpSysDib.CpSvr7034.1" - - -class CpSvr7236(ISysDib, ISysDibEvents): - CLSID = IID("{100A7E1E-1B72-4622-A4CF-FFBA1336A30C}") - PROGID = "CpSysDib.CpSvr7236.1" - - -class CpSvr2221(ISysDib, ISysDibEvents): - CLSID = IID("{C3DE1C2F-54FE-4B1E-B433-4F42A4929618}") - PROGID = "CpSysDib.CpSvr2221.1" - - -class CpSvr7238(ISysDib, ISysDibEvents): - CLSID = IID("{62FBF818-C088-40C1-9B6E-D7CBA632405C}") - PROGID = "CpSysDib.CpSvr7238.1" - - -class CpSvr7151(ISysDib, ISysDibEvents): - CLSID = IID("{250EDB54-764B-4015-979A-2B1819C8F4BA}") - PROGID = "CpSysDib.CpSvr7151.1" - - -class CpSvr7240(ISysDib, ISysDibEvents): - CLSID = IID("{3438271B-2E14-4DCB-B64A-CAD75B5016C5}") - PROGID = "CpSysDib.CpSvr7240.1" - - -class CpSvr7210d(ISysDib, ISysDibEvents): - CLSID = IID("{A92FDBCE-E9F7-425D-8FB7-3ACCDE09264F}") - PROGID = "CpSysDib.CpSvr7210d.1" - - -class CpSvr7210T(ISysDib, ISysDibEvents): - CLSID = IID("{249A0E5B-2FB1-4762-96DE-D7D0C7927796}") - PROGID = "CpSysDib.CpSvr7210T.1" - - -class CpSvr8241(ISysDib, ISysDibEvents): - CLSID = IID("{0F5B7F6F-A5B6-4296-94DB-98373EEE1598}") - PROGID = "CpSysDib.CpSvr8241.1" - - -class CpSvr7049(ISysDib, ISysDibEvents): - CLSID = IID("{D44D2789-F23F-4E3D-959C-E6A399413492}") - PROGID = "CpSysDib.CpSvr7049.1" - - -class FutStockMst(ISysDib, ISysDibEvents): - CLSID = IID("{302903C9-49D8-4D47-9A3F-A2FA150350E7}") - PROGID = "CpSysDib.FutStockMst.1" - - -class FutStockCurS(ISysDib, ISysDibEvents): - CLSID = IID("{0651A2B7-0F47-4233-ACBF-DDEFA06C57E9}") - PROGID = "CpSysDib.FutStockCurS.1" - - -class FutStockWeek(ISysDib, ISysDibEvents): - CLSID = IID("{C8F097B8-BF52-419B-8430-084B596B4AD3}") - PROGID = "CpSysDib.FutStockWeek.1" - - -class CpSvr9841(ISysDib, ISysDibEvents): - CLSID = IID("{5A7EB1B7-BDB3-45E6-9CAA-A75F8C534685}") - PROGID = "CpSysDib.CpSvr9841.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/CpTrade.py b/koapy/backend/daishin_cybos_plus/stub/CpTrade.py deleted file mode 100644 index 349f1b45..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/CpTrade.py +++ /dev/null @@ -1,496 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class ICpTdUtil: - CLSID = IID("{15CA8DD1-1CF9-4544-A1A4-5593CE63A845}") - - def TradeInit(self, Reserved: int = 0) -> int: - ... - - def GoodsList(self, acc: str, Filter: int) -> Any: - ... - - @property - def AccountNumber(self) -> Any: - ... - - -class ICpTdField: - CLSID = IID("{E7BD5AF6-4EB1-47E1-BB3B-9505E2F09F0A}") - - @property - def Name(self) -> str: - ... - - @property - def fid(self) -> int: - ... - - -class ICpTdFields: - CLSID = IID("{F3A9F36B-F36F-462C-B418-F4A31D8FE46F}") - - def __call__(self, Index: int) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpTdField(ICpTdField): - CLSID = IID("{672A5C44-9446-4405-9F0E-1EA1FEFC29ED}") - - -class CpTdFields(ICpTdFields): - CLSID = IID("{4AABFB5F-4AC0-41D5-9458-D670489A8B66}") - - -class ICpTdDib: - CLSID = IID("{F75A3C47-4B29-46E8-AD1C-D34BD89B5143}") - - def GetHeaderValue(self, _MIDL__ICpTdDib0000_: int) -> Any: - ... - - def GetDataValue(self, _MIDL__ICpTdDib0001_: int, _MIDL__ICpTdDib0002_: int) -> Any: - ... - - def GetInputValue(self, _MIDL__ICpTdDib0003_: int) -> Any: - ... - - def SetInputValue(self, _MIDL__ICpTdDib0004_: int, newVal: Any) -> None: - ... - - def GetDibStatus(self) -> int: - ... - - def GetDibMsg1(self) -> str: - ... - - def GetDibMsg2(self) -> str: - ... - - def BlockRequest(self) -> int: - ... - - def BlockRequest2(self, BlockOption: int) -> int: - ... - - def Request(self) -> int: - ... - - @property - def Header(self) -> Any: - ... - - @property - def Data(self) -> Any: - ... - - @property - def Input(self) -> Any: - ... - - @property - def Continue(self) -> int: - ... - - @Continue.setter - def Continue(self, Continue: int) -> None: - ... - - -class ITdDibEvents: - CLSID = IID("{8B55AD34-73A3-4C33-B8CD-C95ED13823CB}") - - @property - def OnReceived(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class ITdDibEventsHandler: - CLSID = IID("{8B55AD34-73A3-4C33-B8CD-C95ED13823CB}") - - def OnReceived(self) -> None: - ... - - -class CpTdUtil(ICpTdUtil): - CLSID = IID("{1172DA0D-1235-4348-880B-10F95AC86E46}") - PROGID = "CpTrade.CpTdUtil.1" - - -class CpTradeKey(ICpTdDib): - CLSID = IID("{0CAA9637-7CAA-4A96-80D2-8CBEAFD66EEE}") - - -class CpTd0311(ICpTdDib, ITdDibEvents): - CLSID = IID("{ACAD853E-9FA9-4165-9CE9-166BF4414AA3}") - PROGID = "CpTrade.CpTd0311.1" - - -class CpTd5341(ICpTdDib, ITdDibEvents): - CLSID = IID("{8203C86A-2282-4225-A79E-A9559357A3BC}") - PROGID = "CpTrade.CpTd5341.1" - - -class CpTd5339(ICpTdDib, ITdDibEvents): - CLSID = IID("{D82177A9-9AD3-4B30-9134-9C28BE43656D}") - PROGID = "CpTrade.CpTd5339.1" - - -class CpTd0312(ICpTdDib, ITdDibEvents): - CLSID = IID("{1497FD6D-0439-47BC-95B3-B838CD32D00F}") - PROGID = "CpTrade.CpTd0312.1" - - -class CpTd0313(ICpTdDib, ITdDibEvents): - CLSID = IID("{CB3DDA0D-E824-4008-8E69-CF168ABB6361}") - PROGID = "CpTrade.CpTd0313.1" - - -class CpTd0303(ICpTdDib, ITdDibEvents): - CLSID = IID("{A4B66D34-D296-477C-B4C2-3900810DF8F3}") - PROGID = "CpTrade.CpTd0303.1" - - -class CpTd0314(ICpTdDib, ITdDibEvents): - CLSID = IID("{15110F2E-4E3A-4921-AF52-EE6BF85AAD6E}") - PROGID = "CpTrade.CpTd0314.1" - - -class CpTd6033(ICpTdDib, ITdDibEvents): - CLSID = IID("{1E090CEF-B084-4961-93C3-92360F4D2226}") - PROGID = "CpTrade.CpTd6033.1" - - -class CpTd5342(ICpTdDib, ITdDibEvents): - CLSID = IID("{4E87EAB5-DB31-4FA6-AE19-47FFFE0672B9}") - PROGID = "CpTrade.CpTd5342.1" - - -class CpTd0315(ICpTdDib, ITdDibEvents): - CLSID = IID("{ED55E435-4C27-48A0-9033-309EF9D88E1F}") - PROGID = "CpTrade.CpTd0315.1" - - -class CpTd0316(ICpTdDib, ITdDibEvents): - CLSID = IID("{91875829-5FDE-4254-BA35-52272D546F8F}") - PROGID = "CpTrade.CpTd0316.1" - - -class CpTd0306(ICpTdDib, ITdDibEvents): - CLSID = IID("{0002AEE1-A91F-4CF8-AD84-13E5844EC471}") - PROGID = "CpTrade.CpTd0306.1" - - -class CpTd0317(ICpTdDib, ITdDibEvents): - CLSID = IID("{60D268EF-1D95-49B2-9E83-35B5DCD2A241}") - PROGID = "CpTrade.CpTd0317.1" - - -class CpTd6740(ICpTdDib, ITdDibEvents): - CLSID = IID("{F717B1BE-567C-4F55-A140-6E02FA7B8BD9}") - - -class CpTd6743R(ICpTdDib, ITdDibEvents): - CLSID = IID("{F1BEF87C-30DC-424E-B5FC-01F1B5E10FED}") - - -class CpTd6750L(ICpTdDib, ITdDibEvents): - CLSID = IID("{6B725C6E-D885-480B-B08C-D6AAF4BB76AC}") - - -class CpTd6751(ICpTdDib, ITdDibEvents): - CLSID = IID("{138A98B2-BA82-4CB9-BFD1-5FD4AE078DDF}") - - -class CpTd6753(ICpTdDib, ITdDibEvents): - CLSID = IID("{1C5CD253-54F6-4175-AD38-0F9BFE7B7B5A}") - - -class CpTd6754(ICpTdDib, ITdDibEvents): - CLSID = IID("{233AA076-0DF8-47DA-BAED-A035138540F8}") - - -class CpTd6831(ICpTdDib, ITdDibEvents): - CLSID = IID("{BB347FF1-D974-4A50-85FB-C751235AE061}") - PROGID = "CpTrade.CpTd6831.1" - - -class CpTd6832(ICpTdDib, ITdDibEvents): - CLSID = IID("{0BF841E1-849B-4AB9-8D85-5821458A437C}") - PROGID = "CpTrade.CpTd6832.1" - - -class CpTd6833(ICpTdDib, ITdDibEvents): - CLSID = IID("{6DCE8A22-6811-4399-9D34-B915D84F0727}") - PROGID = "CpTrade.CpTd6833.1" - - -class CpTd5371(ICpTdDib, ITdDibEvents): - CLSID = IID("{2370A08A-7AE8-4ADE-89A3-09477A941C1D}") - PROGID = "CpTrade.CpTd5371.1" - - -class CpTd3811(ICpTdDib, ITdDibEvents): - CLSID = IID("{EF56DD80-F726-4C1A-A5A8-12D30A2543EF}") - PROGID = "CpTrade.CpTd3811.1" - - -class CpTd5372(ICpTdDib, ITdDibEvents): - CLSID = IID("{BD6AF962-E715-4014-ADC7-7AE2132DB763}") - PROGID = "CpTrade.CpTd5372.1" - - -class CpTd0723(ICpTdDib, ITdDibEvents): - CLSID = IID("{F4294E75-719A-4728-A240-161773E1C964}") - PROGID = "CpTrade.CpTd0723.1" - - -class CpTd6722(ICpTdDib, ITdDibEvents): - CLSID = IID("{BE3394F1-4D4E-4508-923E-865CDAB9DCC8}") - PROGID = "CpTrade.CpTd6722.1" - - -class CpTd6841(ICpTdDib, ITdDibEvents): - CLSID = IID("{B6E99909-F65C-4DF9-9C0A-8EF2318610D0}") - PROGID = "CpTrade.CpTd6841.1" - - -class CpTd6842(ICpTdDib, ITdDibEvents): - CLSID = IID("{20A0CCAB-B4C8-4671-9624-AF420FCA1831}") - PROGID = "CpTrade.CpTd6842.1" - - -class CpTd6843(ICpTdDib, ITdDibEvents): - CLSID = IID("{97ABDC4A-3287-4D8C-822D-BB1476504E23}") - PROGID = "CpTrade.CpTd6843.1" - - -class CpTd0322(ICpTdDib, ITdDibEvents): - CLSID = IID("{BCF369E7-2657-4BD5-AE57-3E06A0FE461B}") - PROGID = "CpTrade.CpTd0322.1" - - -class CpTd0326(ICpTdDib, ITdDibEvents): - CLSID = IID("{BCB65B18-E3E5-4099-9070-B602D9B4BB42}") - PROGID = "CpTrade.CpTd0326.1" - - -class CpTd0355(ICpTdDib, ITdDibEvents): - CLSID = IID("{40A1A9C2-43E3-4BD8-A0A6-223C5BC5E86F}") - PROGID = "CpTrade.CpTd0355.1" - - -class CpTd0356(ICpTdDib, ITdDibEvents): - CLSID = IID("{C82BFF91-9F5C-400D-9B52-40BA3AC47F73}") - PROGID = "CpTrade.CpTd0356.1" - - -class CpTdNew5331A(ICpTdDib, ITdDibEvents): - CLSID = IID("{A01B00EA-B723-4F29-884E-F12F6760F248}") - PROGID = "CpTrade.CpTdNew5331A.1" - - -class CpTdNew5331B(ICpTdDib, ITdDibEvents): - CLSID = IID("{99EE8587-50FE-4520-8551-BEE017B3C16F}") - PROGID = "CpTrade.CpTdNew5331B.1" - - -class CpTd6197(ICpTdDib, ITdDibEvents): - CLSID = IID("{4DE84A1D-FB39-4B57-8E61-0216777A1B31}") - PROGID = "CpTrade.CpTd6197.1" - - -class CpTd0386(ICpTdDib, ITdDibEvents): - CLSID = IID("{A7984EA5-C50B-4DF3-A92C-7E6CC7AFB20A}") - PROGID = "CpTrade.CpTd0386.1" - - -class CpTd0387(ICpTdDib, ITdDibEvents): - CLSID = IID("{EB4C7EC4-5D99-454B-930C-12081EA02658}") - PROGID = "CpTrade.CpTd0387.1" - - -class CpTd0389(ICpTdDib, ITdDibEvents): - CLSID = IID("{C24DC073-D02C-409A-8358-C8BEB483BE41}") - PROGID = "CpTrade.CpTd0389.1" - - -class CpTd9065(ICpTdDib, ITdDibEvents): - CLSID = IID("{DA92E1FD-717F-4549-BB5C-90391302E84F}") - PROGID = "CpTrade.CpTd9065.1" - - -class CpTd9081(ICpTdDib, ITdDibEvents): - CLSID = IID("{8B8DA4AD-72A4-4D06-B249-90273D97CC14}") - PROGID = "CpTrade.CpTd9081.1" - - -class CpTd9082(ICpTdDib, ITdDibEvents): - CLSID = IID("{4C91160F-8C08-432D-A809-48A908D96016}") - PROGID = "CpTrade.CpTd9082.1" - - -class CpTd9083(ICpTdDib, ITdDibEvents): - CLSID = IID("{D44BB8E2-8E72-42E5-8B83-0D70E4338128}") - PROGID = "CpTrade.CpTd9083.1" - - -class CpTd9084(ICpTdDib, ITdDibEvents): - CLSID = IID("{D178011D-1CEB-4250-BB80-F9D42776BB46}") - PROGID = "CpTrade.CpTd9084.1" - - -class CpTd9085(ICpTdDib, ITdDibEvents): - CLSID = IID("{D585FF27-E7C3-484F-8F19-CAFF39CE0A49}") - PROGID = "CpTrade.CpTd9085.1" - - -class CpTd0354(ICpTdDib, ITdDibEvents): - CLSID = IID("{63A29BB8-469C-4965-B4E2-FC1A545E4E2B}") - PROGID = "CpTrade.CpTd0354.1" - - -class CpTd0323(ICpTdDib, ITdDibEvents): - CLSID = IID("{5BE98374-8EE2-4C9C-AF7A-46D33E12F476}") - PROGID = "CpTrade.CpTd0323.1" - - -class CpTd0359(ICpTdDib, ITdDibEvents): - CLSID = IID("{E476724F-D2F2-4BB9-86E5-C350891E4FB4}") - PROGID = "CpTrade.CpTd0359.1" - - -class CpTd0388(ICpTdDib, ITdDibEvents): - CLSID = IID("{C9410BA8-F7DB-4433-BEBA-670FC9D71C74}") - PROGID = "CpTrade.CpTd0388.1" - - -class CpTd0721F(ICpTdDib, ITdDibEvents): - CLSID = IID("{CE7160AC-297A-4274-9AEB-26F9D1312DF8}") - PROGID = "CpTrade.CpTd0721F.1" - - -class CpTd0732(ICpTdDib, ITdDibEvents): - CLSID = IID("{FCC8B385-6ABB-44E5-AD6C-78448F901895}") - PROGID = "CpTrade.CpTd0732.1" - - -class CpTdNew9061(ICpTdDib, ITdDibEvents): - CLSID = IID("{6C7B3B4E-7D8B-4598-AE1A-518E8FD459C2}") - PROGID = "CpTrade.CpTdNew9061.1" - - -class CpTdNew9064(ICpTdDib, ITdDibEvents): - CLSID = IID("{3AE88694-EAE6-4DDE-AB31-CA5A1408319B}") - PROGID = "CpTrade.CpTdNew9064.1" - - -class CpTd3661(ICpTdDib, ITdDibEvents): - CLSID = IID("{AB94158B-0724-46B5-985D-75D818856A56}") - PROGID = "CpTrade.CpTd3661.1" - - -class CpTd3661D(ICpTdDib, ITdDibEvents): - CLSID = IID("{9842E02C-187C-4B0B-9120-5D02FEB58474}") - PROGID = "CpTrade.CpTd3661D.1" - - -class CmeOrder(ICpTdDib, ITdDibEvents): - CLSID = IID("{FB214CC6-2265-4078-9405-FEF5D909B227}") - PROGID = "cptrade.CmeOrder.1" - - -class CmeBalance(ICpTdDib, ITdDibEvents): - CLSID = IID("{DEAC8F35-DD30-4C02-B105-9F558863D797}") - PROGID = "cptrade.CmeBalance.1" - - -class CmeConclusion(ICpTdDib, ITdDibEvents): - CLSID = IID("{F415CACE-CCFF-4F7A-8ACD-4C3045DDD2D1}") - PROGID = "CpTrade.CmeConclusion.1" - - -class CmeNoConclusion(ICpTdDib, ITdDibEvents): - CLSID = IID("{6C242F93-DE5E-4039-961F-4C116D74BE66}") - PROGID = "CpTrade.CmeNoConclusion.1" - - -class EurexBalance(ICpTdDib, ITdDibEvents): - CLSID = IID("{1D18474B-29CA-45B5-A3A5-A75B3593888B}") - PROGID = "CpTrade.EurexBalance.1" - - -class EurexConclusion(ICpTdDib, ITdDibEvents): - CLSID = IID("{47FA1A84-D56E-4AC7-A176-D9A2BCF01C72}") - PROGID = "CpTrade.EurexConclusion.1" - - -class EurexNoConclusion(ICpTdDib, ITdDibEvents): - CLSID = IID("{C822BB56-2BB3-412F-BFD7-9DE5E42E2A48}") - PROGID = "CpTrade.EurexNoConclusion.1" - - -class EurexOrder(ICpTdDib, ITdDibEvents): - CLSID = IID("{62055D8A-2A2C-482A-AB61-4B6808A6B95F}") - PROGID = "cptrade.EurexOrder.1" - - -class CmeConclusionDay(ICpTdDib, ITdDibEvents): - CLSID = IID("{2E24A4D5-749A-4E08-98B7-081897BF6612}") - PROGID = "cptrade.CmeConclusionDay.1" - - -class EurexConclusionDay(ICpTdDib, ITdDibEvents): - CLSID = IID("{81C12AD3-D154-4908-81FF-01C6D65A052E}") - PROGID = "cptrade.EurexConclusionDay.1" - - -class CmeEurexProfitLoss(ICpTdDib, ITdDibEvents): - CLSID = IID("{7163F543-C48D-4BF4-8CB9-723D1160C03A}") - PROGID = "CpTrade.CmeEurexProfitLoss.1" - - -class CpTd9197(ICpTdDib, ITdDibEvents): - CLSID = IID("{8BA40942-F695-44D4-A159-BBD40E92F35C}") - PROGID = "CpTrade.CpTd9197.1" - - -class CpTd0711AtmAll(ICpTdDib, ITdDibEvents): - CLSID = IID("{DED73E82-8BC5-44CF-8B68-6D4D0A629D4F}") - PROGID = "cptrade.CpTd0711AtmAll.1" - - -class CpTd6128C(ICpTdDib, ITdDibEvents): - CLSID = IID("{BB483629-435C-4852-AF05-7B37A80F7661}") - PROGID = "cptrade.CpTd6128C.1" - - -class CpTd6128A(ICpTdDib, ITdDibEvents): - CLSID = IID("{86551C2A-9893-4DB6-A917-AF2D048BA13A}") - PROGID = "cptrade.CpTd6128A.1" - - -class CpTd6126(ICpTdDib, ITdDibEvents): - CLSID = IID("{8D794BED-A116-471A-8298-AAB673C3CC58}") - PROGID = "cptrade.CpTd6126.1" - - -class CpTd2034(ICpTdDib, ITdDibEvents): - CLSID = IID("{8F3408DA-8936-4902-AA2D-13AFBEB2561A}") - PROGID = "cptrade.CpTd2034.1" - - -class CpTd6032(ICpTdDib, ITdDibEvents): - CLSID = IID("{F93732D1-FC68-4C04-A0F2-4A66971D581B}") - PROGID = "cptrade.CpTd6032.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/CpUtil.py b/koapy/backend/daishin_cybos_plus/stub/CpUtil.py deleted file mode 100644 index 07510274..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/CpUtil.py +++ /dev/null @@ -1,659 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class ICpUserInfo: - CLSID = IID("{363AF9F5-0612-4E75-A563-211851B45A16}") - - def VerifyUserInfo(self, SocialNo: str, UserName: str) -> int: - ... - - @property - def ComID(self) -> str: - ... - - -class CpUserInfo(ICpUserInfo): - CLSID = IID("{DB656203-951A-4D6A-972E-0138DEBD6648}") - PROGID = "CpUtil.CpUserInfo.1" - - -class ICpStockCode: - CLSID = IID("{081AAEAA-DFAF-4B7F-A53A-0D1E4AC58584}") - - def CodeToName(self, code: str) -> str: - ... - - def FullCodeToName(self, code: str) -> str: - ... - - def GetCount(self) -> int: - ... - - def GetData(self, type: int, index: int) -> Any: - ... - - def CodeToFullCode(self, code: str) -> str: - ... - - def FullCodeToCode(self, code: str) -> str: - ... - - def NameToCode(self, name: str) -> str: - ... - - def CodeToIndex(self, code: str) -> int: - ... - - def GetPriceUnit(self, code: str, basePrice: int, directionUp: bool = True) -> int: - ... - - -class CpStockCode(ICpStockCode): - CLSID = IID("{2297F381-FFB1-45C6-AA80-4C6913F45E91}") - PROGID = "CpUtil.CpStockCode.1" - - -class ICpFutureCode: - CLSID = IID("{FDDF6F98-B0AE-4B86-8C62-CC4469075F65}") - - def GetCount(self) -> int: - ... - - def GetData(self, type: int, index: int) -> Any: - ... - - def CodeToName(self, code: str) -> str: - ... - - -class CpFutureCode(ICpFutureCode): - CLSID = IID("{15A37730-A973-47D7-9058-2686097642F8}") - PROGID = "CpUtil.CpFutureCode.1" - - -class CpKFutureCode(ICpFutureCode): - CLSID = IID("{E6BFF246-8B47-4833-AE20-F853BDAA3248}") - PROGID = "CpUtil.CpKFutureCode.1" - - -class ICpOptionCode: - CLSID = IID("{312ADE72-2C5C-4084-ADCE-9BBBAFEFAD56}") - - def GetCount(self) -> int: - ... - - def GetData(self, type: int, index: int) -> Any: - ... - - def CodeToName(self, code: str) -> str: - ... - - -class CpOptionCode(ICpOptionCode): - CLSID = IID("{7566755F-36AD-43EF-B388-4CC62CA94279}") - PROGID = "CpUtil.CpOptionCode.1" - - -class ICpSoptionCode: - CLSID = IID("{B41FB07E-3901-4FF8-9D66-1C06D50EC5FC}") - - def GetCount(self) -> int: - ... - - def GetData(self, type: int, index: int) -> Any: - ... - - def CodeToName(self, code: str) -> str: - ... - - -class CpSoptionCode(ICpSoptionCode): - CLSID = IID("{F23D75C0-A0AC-4988-865C-54B3B9D009B2}") - PROGID = "CpUtil.CpSoptionCode.1" - - -class ICpCybos: - CLSID = IID("{3722B490-A340-45C5-BDA5-3C736DDEB423}") - - def GetLimitRemainCount(self, limitType: int) -> int: - ... - - def CreonPlusConnect(self, bstID: str, bstPWD: str, bstPKI: str) -> str: - ... - - def CybosPlusConnect(self, bstID: str, bstPWD: str, bstPKI: str) -> str: - ... - - def PlusDisconnect(self) -> None: - ... - - def GetLimitRemainTime(self, limitType: int) -> int: - ... - - @property - def IsConnect(self) -> int: - ... - - @property - def ServerType(self) -> int: - ... - - @property - def LimitRequestRemainTime(self) -> int: - ... - - -class ICpCybosEvents: - CLSID = IID("{17F70631-56E5-40FC-B94F-44ADD3A850B1}") - - @property - def OnDisconnect(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class ICpCybosEventsHandler: - CLSID = IID("{17F70631-56E5-40FC-B94F-44ADD3A850B1}") - - def OnDisconnect(self) -> int: - ... - - -class CpCybos(ICpCybos, ICpCybosEvents): - CLSID = IID("{19A11288-2B28-45C4-8CD4-3A12B60C3BD7}") - PROGID = "CpUtil.CpCybos.1" - - -class ICpCodeMgr: - CLSID = IID("{6893A6D3-03FD-46EB-BB0E-28A22D3AEC9B}") - - def GetGroupCodeList(self, GroupCode: int) -> Any: - ... - - def CodeToName(self, code: str) -> str: - ... - - def GetUsCodeList(self, type: int = 1) -> Any: - ... - - def GetUsCodeName(self, code: str) -> str: - ... - - def GetStockMarginRate(self, code: str) -> int: - ... - - def GetStockMemeMin(self, code: str) -> int: - ... - - def GetStockElwBasketCodeList(self, bstrCode: str) -> Any: - ... - - def GetStockElwBasketCompList(self, bstrCode: str) -> Any: - ... - - def GetMarketStartTime(self) -> int: - ... - - def GetMarketEndTime(self) -> int: - ... - - def GetStockIndustryCode(self, bstrCode: str) -> str: - ... - - def GetStockMarketKind(self, bstrCode: str) -> int: - ... - - def GetStockControlKind(self, bstrCode: str) -> int: - ... - - def GetStockSupervisionKind(self, bstrCode: str) -> int: - ... - - def GetStockCapital(self, bstrCode: str) -> int: - ... - - def GetStockFiscalMonth(self, bstrCode: str) -> int: - ... - - def GetStockGroupCode(self, bstrCode: str) -> int: - ... - - def GetStockKospi200Kind(self, bstrCode: str) -> int: - ... - - def GetStockStatusKind(self, bstrCode: str) -> int: - ... - - def GetGroupList(self) -> Any: - ... - - def GetGroupName(self, bstrCode: str) -> str: - ... - - def GetIndustryList(self) -> Any: - ... - - def GetKrxIndustryList(self) -> Any: - ... - - def GetIndustryName(self, bstrCode: str) -> str: - ... - - def GetMemberList(self) -> Any: - ... - - def GetMemberName(self, bstrCode: str) -> str: - ... - - def GetKosdaqIndustry1List(self) -> Any: - ... - - def GetKosdaqIndustry2List(self) -> Any: - ... - - def GetStockListByMarket(self, MarketKind: int) -> Any: - ... - - def GetStockSectionKind(self, bstrCode: str) -> int: - ... - - def GetStockLacKind(self, bstrCode: str) -> int: - ... - - def GetStockCodeByName(self, bstrName: str) -> str: - ... - - def GetStockListedDate(self, bstrName: str) -> int: - ... - - def GetStockMaxPrice(self, bstrName: str) -> int: - ... - - def GetStockMinPrice(self, bstrName: str) -> int: - ... - - def GetStockParPrice(self, bstrName: str) -> int: - ... - - def GetStockStdPrice(self, bstrName: str) -> int: - ... - - def GetStockYdOpenPrice(self, bstrName: str) -> int: - ... - - def GetStockYdHighPrice(self, bstrName: str) -> int: - ... - - def GetStockYdLowPrice(self, bstrName: str) -> int: - ... - - def GetStockYdClosePrice(self, bstrName: str) -> int: - ... - - def GetStockParPriceChageType(self, bstrName: str) -> int: - ... - - def IsStockCreditEnable(self, bstrName: str) -> int: - ... - - def GetVentureKind(self, bstrName: str) -> int: - ... - - def IsStockLoanEnable(self, bstrName: str) -> int: - ... - - def GetStockEngName(self, bstrCode: str) -> str: - ... - - def GetWorkDate(self) -> str: - ... - - def IsSPAC(self, bstrName: str) -> int: - ... - - def IsLendingStockEnable(self, bstrName: str) -> int: - ... - - def GetMiniFutureList(self) -> Any: - ... - - def GetMiniOptionList(self) -> Any: - ... - - def ReLoadPortData(self) -> None: - ... - - def GetTickUnit(self, bstrCode: str) -> float: - ... - - def GetTickValue(self, bstrCode: str) -> float: - ... - - def OvFutCodeToName(self, code: str) -> str: - ... - - def OvFutGetAllCodeList(self) -> Any: - ... - - def OvFutGetExchList(self) -> Any: - ... - - def OvFutGetLastTradeDate(self, code: str) -> int: - ... - - def OvFutGetExchCode(self, code: str) -> str: - ... - - def OvFutGetProdCode(self, code: str) -> str: - ... - - def IsBigListingStock(self, code: str) -> int: - ... - - def IsTradeCondition(self, code: str) -> int: - ... - - def GetStartTime(self, code: str) -> int: - ... - - def GetEndTime(self, code: str) -> int: - ... - - def IsFrnMember(self, code: str) -> int: - ... - - def GetStockFutureList(self) -> Any: - ... - - def GetStockFutureBaseList(self) -> Any: - ... - - def GetStockFutureListByBaseCode(self, bstrCode: str) -> Any: - ... - - def GetStockFutureBaseCode(self, bstrCode: str) -> str: - ... - - def IsStockArrgSby(self, code: str) -> int: - ... - - def IsStockIoi(self, code: str) -> int: - ... - - def GetOverHeating(self, bstrCode: str) -> int: - ... - - def IsStockLtgStkCnInsfItm(self, code: str) -> int: - ... - - def GetKostarOptionList(self) -> Any: - ... - - def GetFOTradeUnit(self, bstrCode: str) -> float: - ... - - def GetKostarFutureList(self) -> Any: - ... - - -class CpCodeMgr(ICpCodeMgr): - CLSID = IID("{995B5ABE-ED4B-4D04-B46D-6238AB66EA71}") - PROGID = "CpUtil.CpCodeMgr.1" - - -class ICpElwCode: - CLSID = IID("{A162F0D1-894A-48D1-BDF4-E8589EA7607B}") - - def GetCount(self) -> int: - ... - - def GetData(self, type: int, index: int) -> Any: - ... - - def CodeToName(self, code: str) -> str: - ... - - def GetStockElwBaseList(self) -> Any: - ... - - def GetStockElwBaseCode(self, bstrCode: str) -> str: - ... - - def GetStockElwBaseName(self, bstrCode: str) -> str: - ... - - def GetStockElwIssuerList(self) -> Any: - ... - - def GetStockElwLpCodeList(self, bstrCode: str) -> Any: - ... - - def GetNameByStockElwLpCode(self, bstrLpCode: str) -> str: - ... - - def GetStockElwBasketCodeList(self, bstrCode: str) -> Any: - ... - - def GetStockElwBasketCompList(self, bstrCode: str) -> Any: - ... - - def GetStockElwCodeListByBaseCode(self, bstrCode: str) -> Any: - ... - - def GetStockElwCodeListByRightType(self, eRightType: int) -> Any: - ... - - -class CpElwCode(ICpElwCode): - CLSID = IID("{3AB3C774-9971-4BD3-9393-183641A5028D}") - PROGID = "CpUtil.CpElwCode.1" - - -class ICpUsCode: - CLSID = IID("{E1698433-8C49-4075-BDF8-0C0A23C61A2A}") - - def GetUsCodeList(self, USTYPE: int) -> Any: - ... - - def GetNameByUsCode(self, bstrUsCode: str) -> str: - ... - - -class CpUsCode(ICpUsCode): - CLSID = IID("{03948751-CF92-443E-81D9-94351E0F51FF}") - PROGID = "CpUtil.CpUsCode.1" - - -class ICpCalcOptGreeks: - CLSID = IID("{AE72A9FD-E459-4678-B8CA-7417BEF26142}") - - def Calculate(self) -> None: - ... - - @property - def TV(self) -> float: - ... - - @property - def Delta(self) -> float: - ... - - @property - def Gamma(self) -> float: - ... - - @property - def Theta(self) -> float: - ... - - @property - def Vega(self) -> float: - ... - - @property - def Rho(self) -> float: - ... - - @property - def IV(self) -> float: - ... - - @property - def CallPutType(self) -> None: - ... - - @CallPutType.setter - def CallPutType(self, CallPutType: int) -> None: - ... - - @property - def Price(self) -> None: - ... - - @Price.setter - def Price(self, Price: float) -> None: - ... - - @property - def UnderPrice(self) -> None: - ... - - @UnderPrice.setter - def UnderPrice(self, UnderPrice: float) -> None: - ... - - @property - def ExerPrice(self) -> None: - ... - - @ExerPrice.setter - def ExerPrice(self, ExerPrice: float) -> None: - ... - - @property - def VolatilityType(self) -> None: - ... - - @VolatilityType.setter - def VolatilityType(self, VolatilityType: int) -> None: - ... - - @property - def Volatility(self) -> None: - ... - - @Volatility.setter - def Volatility(self, Volatility: float) -> None: - ... - - @property - def ExpirDays(self) -> None: - ... - - @ExpirDays.setter - def ExpirDays(self, ExpirDays: int) -> None: - ... - - @property - def RFInterRate(self) -> None: - ... - - @RFInterRate.setter - def RFInterRate(self, RFInterRate: float) -> None: - ... - - @property - def DividRate(self) -> None: - ... - - @DividRate.setter - def DividRate(self, DividRate: float) -> None: - ... - - -class CpCalcOptGreeks(ICpCalcOptGreeks): - CLSID = IID("{BA69760D-1698-4BC1-8947-E7F2D07F2173}") - PROGID = "CpUtil.CpCalcOptGreeks.1" - - -class ICpBondCode: - CLSID = IID("{D226367D-66EC-42FE-AED5-696F697AFB6D}") - - @property - def code(self) -> str: - ... - - @property - def name(self) -> str: - ... - - @property - def type(self) -> int: - ... - - @property - def Remain(self) -> int: - ... - - @property - def Issue(self) -> int: - ... - - @property - def Interest(self) -> int: - ... - - @property - def IssueDate(self) -> int: - ... - - @property - def ExpirationDate(self) -> int: - ... - - @property - def Retail(self) -> int: - ... - - @property - def CouponRate(self) -> float: - ... - - @property - def InterestShortName(self) -> str: - ... - - @property - def InterestCycle(self) -> int: - ... - - @property - def RiskLevel(self) -> str: - ... - - -class CpBondCode(ICpBondCode): - CLSID = IID("{8B4B7EFD-7BE3-4C82-A3A7-1E741BB6A2B1}") - - -class ICpBondCodes: - CLSID = IID("{C09E3D05-D1D5-41FE-9DCF-1900FCB69708}") - - def __call__(self, _MIDL__ICpBondCodes0000_: Any) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpBondCodes(ICpBondCodes): - CLSID = IID("{73E62CE2-EB0C-49B2-94B6-029527C9DADA}") - PROGID = "CpUtil.CpBondCodes.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/DsCbo1.py b/koapy/backend/daishin_cybos_plus/stub/DsCbo1.py deleted file mode 100644 index dce3b854..00000000 --- a/koapy/backend/daishin_cybos_plus/stub/DsCbo1.py +++ /dev/null @@ -1,608 +0,0 @@ -from collections.abc import Iterator -from typing import Any, Callable, Union - -from pythoncom import Empty, Missing -from pywintypes import IID, Time - -from koapy.common import EventInstance - - -class IDib: - CLSID = IID("{33518A10-0931-11D4-8231-00105A7C4F8C}") - - def Request(self) -> None: - ... - - def Subscribe(self) -> None: - ... - - def Unsubscribe(self) -> None: - ... - - def GetHeaderValue(self, _MIDL__IDib0000_: int) -> Any: - ... - - def GetDataValue(self, _MIDL__IDib0001_: int, _MIDL__IDib0002_: int) -> Any: - ... - - def GetInputValue(self, _MIDL__IDib0003_: int) -> Any: - ... - - def SetInputValue(self, _MIDL__IDib0004_: int, newVal: Any) -> None: - ... - - def GetDibStatus(self) -> int: - ... - - def GetDibMsg1(self) -> str: - ... - - def GetDibMsg2(self) -> str: - ... - - def BlockRequest(self) -> int: - ... - - def SubscribeLatest(self) -> None: - ... - - def BlockRequest2(self, BlockOption: int) -> int: - ... - - @property - def Header(self) -> Any: - ... - - @property - def Data(self) -> Any: - ... - - @property - def Input(self) -> Any: - ... - - @property - def Continue(self) -> int: - ... - - -class IDibEvents: - CLSID = IID("{B8944520-09C3-11D4-8232-00105A7C4F8C}") - - @property - def OnReceived(self) -> Union[EventInstance, Callable[[], None]]: - ... - - -class IDibEventsHandler: - CLSID = IID("{B8944520-09C3-11D4-8232-00105A7C4F8C}") - - def OnReceived(self) -> None: - ... - - -class ICpField: - CLSID = IID("{85934404-08FD-11D4-8231-00105A7C4F8C}") - - @property - def Name(self) -> str: - ... - - @property - def fid(self) -> int: - ... - - -class ICpFields: - CLSID = IID("{55D0C6E4-0966-11D4-8232-00105A7C4F8C}") - - def __call__(self, Index: int) -> Any: - ... - - def __len__(self) -> int: - ... - - def __iter__(self) -> Iterator[Any]: - ... - - -class CpField(ICpField): - CLSID = IID("{85934405-08FD-11D4-8231-00105A7C4F8C}") - - -class CpFields(ICpFields): - CLSID = IID("{55D0C6E5-0966-11D4-8232-00105A7C4F8C}") - - -class StockMst(IDib, IDibEvents): - CLSID = IID("{9FF543E2-FB11-11D3-8224-00105A7C4F8C}") - PROGID = "Dscbo1.StockMst.1" - - -class StockCur(IDib, IDibEvents): - CLSID = IID("{55D0C6E7-0966-11D4-8232-00105A7C4F8C}") - PROGID = "Dscbo1.StockCur.1" - - -class StockBid(IDib, IDibEvents): - CLSID = IID("{D6122124-0B4C-11D4-8234-00105A7C4F8C}") - PROGID = "Dscbo1.StockBid.1" - - -class StockFrnord(IDib, IDibEvents): - CLSID = IID("{48096137-0B62-11D4-8234-00105A7C4F8C}") - PROGID = "Dscbo1.StockFrnord.1" - - -class StockJpbid(IDib, IDibEvents): - CLSID = IID("{4809613A-0B62-11D4-8234-00105A7C4F8C}") - PROGID = "Dscbo1.StockJpbid.1" - - -class StockJpbid2(IDib, IDibEvents): - CLSID = IID("{4809613F-0B62-11D4-8234-00105A7C4F8C}") - PROGID = "Dscbo1.StockJpbid2.1" - - -class StockCbchk(IDib, IDibEvents): - CLSID = IID("{5B886BA4-0B8E-11D4-8235-00105A7C4F8C}") - PROGID = "Dscbo1.StockCbchk.1" - - -class StockMember(IDib, IDibEvents): - CLSID = IID("{02CAF55C-0C31-11D4-8236-00105A7C4F8C}") - PROGID = "Dscbo1.StockMember.1" - - -class StockMember1(IDib, IDibEvents): - CLSID = IID("{02CAF560-0C31-11D4-8236-00105A7C4F8C}") - PROGID = "Dscbo1.StockMember1.1" - - -class StockWeek(IDib, IDibEvents): - CLSID = IID("{7C79B1F6-0E74-11D4-823A-00105A7C4F8C}") - PROGID = "Dscbo1.StockWeek.1" - - -class CbGraph1(IDib, IDibEvents): - CLSID = IID("{8A1D75A5-0F42-11D4-823D-00105A7C4F8C}") - PROGID = "Dscbo1.CbGraph1.1" - - -class FutureMst(IDib, IDibEvents): - CLSID = IID("{1583EA45-B4D3-4B3A-8018-A0FDF8334619}") - PROGID = "Dscbo1.FutureMst.1" - - -class FutureCurr(IDib, IDibEvents): - CLSID = IID("{8F101465-F973-4601-ABF6-7B281A79C93C}") - PROGID = "Dscbo1.FutureCurr.1" - - -class FutureIndexi(IDib, IDibEvents): - CLSID = IID("{B28635B1-FF2B-4E03-98CC-427D71AA5AC4}") - PROGID = "Dscbo1.FutureIndexi.1" - - -class FutureWide(IDib, IDibEvents): - CLSID = IID("{9D5B7EF6-30C3-43F7-B9F5-6AD9A3CE6A26}") - PROGID = "Dscbo1.FutureWide.1" - - -class FutureMo1(IDib, IDibEvents): - CLSID = IID("{8F86C563-8079-47FD-979E-6C4C7D647786}") - PROGID = "Dscbo1.FutureMo1.1" - - -class OptionMst(IDib, IDibEvents): - CLSID = IID("{B040FF23-27CD-46B2-BDC8-E7E793509C65}") - PROGID = "Dscbo1.OptionMst.1" - - -class OptionCur(IDib, IDibEvents): - CLSID = IID("{2A90886E-86C7-4E37-94BF-D66FD36426F9}") - PROGID = "Dscbo1.OptionCur.1" - - -class OptionMo(IDib, IDibEvents): - CLSID = IID("{505B3ED8-392F-482D-A0C4-6D40F9E7EA72}") - PROGID = "Dscbo1.OptionMo.1" - - -class OptionGreek(IDib, IDibEvents): - CLSID = IID("{F39298B4-74D1-4699-AE7D-82C2CC428E25}") - PROGID = "Dscbo1.OptionGreek.1" - - -class OptionGen(IDib, IDibEvents): - CLSID = IID("{309CFF13-AE6E-48BD-8BE0-13B75D33D3E7}") - PROGID = "Dscbo1.OptionGen.1" - - -class OptionCallput(IDib, IDibEvents): - CLSID = IID("{0E581B11-5E74-4A79-8609-AF117BDB88E0}") - PROGID = "Dscbo1.OptionCallput.1" - - -class StockIndexir(IDib, IDibEvents): - CLSID = IID("{1C95CC46-DDC7-4015-8D06-7028FACDE801}") - PROGID = "Dscbo1.StockIndexir.1" - - -class StockIndexis(IDib, IDibEvents): - CLSID = IID("{354E2635-A0AB-4511-BCD9-13C187A37C89}") - PROGID = "Dscbo1.StockIndexis.1" - - -class FutureBid1(IDib, IDibEvents): - CLSID = IID("{12A49893-A2E9-42A0-9DD4-C28851E597D0}") - PROGID = "Dscbo1.FutureBid1.1" - - -class StockMstm(IDib, IDibEvents): - CLSID = IID("{92372A60-C14C-4B8B-A656-1BB5C17F84AC}") - PROGID = "Dscbo1.StockMstm.1" - - -class FutureIndexh(IDib, IDibEvents): - CLSID = IID("{A8341025-9D81-467C-8D44-5F569BF37842}") - PROGID = "Dscbo1.FutureIndexh.1" - - -class StockStu(IDib, IDibEvents): - CLSID = IID("{1D9E7343-8C92-430A-9C8D-F8C6DCF3D635}") - PROGID = "Dscbo1.StockStu.1" - - -class FutureFtu(IDib, IDibEvents): - CLSID = IID("{CEE55BF3-DE0B-46B9-AD5E-108D875E54FE}") - PROGID = "Dscbo1.FutureFtu.1" - - -class OptionFtu(IDib, IDibEvents): - CLSID = IID("{70A9C960-FBFF-4981-A081-3F323B3A439F}") - PROGID = "Dscbo1.OptionFtu.1" - - -class FutureGr1(IDib, IDibEvents): - CLSID = IID("{1EF6F3EE-F43F-4FEC-845A-44D4CF769272}") - PROGID = "Dscbo1.FutureGr1.1" - - -class OptionGr1(IDib, IDibEvents): - CLSID = IID("{65735FE8-5B16-4285-A832-532E5FFC9B38}") - PROGID = "Dscbo1.OptionGr1.1" - - -class CpSvr7225(IDib, IDibEvents): - CLSID = IID("{C12D47E0-BACB-47AE-BC6C-4BD5744A8680}") - PROGID = "Dscbo1.CpSvr7225.1" - - -class PgAtime8112(IDib, IDibEvents): - CLSID = IID("{44F25C73-57E6-4BAA-9369-9B6F42CD5D55}") - PROGID = "Dscbo1.PgAtime8112.1" - - -class StockAdS(IDib, IDibEvents): - CLSID = IID("{5CBBF6AD-6896-40A2-BC7F-630C274627BE}") - PROGID = "Dscbo1.StockAdS.1" - - -class StockAdR(IDib, IDibEvents): - CLSID = IID("{7630F872-FDF8-4880-BE46-C7B912CA5CC1}") - PROGID = "Dscbo1.StockAdR.1" - - -class CpConclusion(IDib, IDibEvents): - CLSID = IID("{72FDAF04-F87B-47E1-9396-0A7C98F4E5C5}") - PROGID = "Dscbo1.CpConclusion.1" - - -class StockAdkS(IDib, IDibEvents): - CLSID = IID("{58172CD3-659D-45C7-8E5E-9C65049C8202}") - PROGID = "Dscbo1.StockAdkS.1" - - -class StockAdkR(IDib, IDibEvents): - CLSID = IID("{0D60B192-F361-4353-8B23-44514911FA6F}") - PROGID = "Dscbo1.StockAdkR.1" - - -class CpFConclusion(IDib, IDibEvents): - CLSID = IID("{F33F2A8E-A1F8-40C3-9F0D-8001E409B18A}") - PROGID = "Dscbo1.CpFConclusion.1" - - -class FutureWeek1(IDib, IDibEvents): - CLSID = IID("{0D4CDCEC-DD27-402B-8036-094CB9D18F3E}") - PROGID = "Dscbo1.FutureWeek1.1" - - -class OptionBid(IDib, IDibEvents): - CLSID = IID("{137C4125-1323-469D-86BC-962C2C9CAC11}") - PROGID = "Dscbo1.OptionBid.1" - - -class FutureK200(IDib, IDibEvents): - CLSID = IID("{52F1E791-07E5-49DD-ADBD-4F59CEE7E56D}") - PROGID = "Dscbo1.FutureK200.1" - - -class OptionWeek(IDib, IDibEvents): - CLSID = IID("{B946B892-D57E-4D7D-A8A2-D857EC54C419}") - PROGID = "Dscbo1.OptionWeek.1" - - -class OptionInfo(IDib, IDibEvents): - CLSID = IID("{F68D10E7-FEED-4FDE-BBAA-D1FF881771BA}") - PROGID = "Dscbo1.OptionInfo.1" - - -class OptionTV(IDib, IDibEvents): - CLSID = IID("{594BC899-B2DF-4C32-83DF-6E0AA542B8DC}") - PROGID = "Dscbo1.OptionTV.1" - - -class CpSvr7223(IDib, IDibEvents): - CLSID = IID("{1F1E0B94-8A20-4F9E-A89D-53C3E5C1EC56}") - PROGID = "Dscbo1.CpSvr7223.1" - - -class CpSvr8092S(IDib, IDibEvents): - CLSID = IID("{362648C3-A91F-4BD6-B65C-354FCE9FCC5E}") - PROGID = "Dscbo1.CpSvr8092S.1" - - -class CpSvr8561(IDib, IDibEvents): - CLSID = IID("{71A629F4-D2A8-4F0C-AD48-B2B6494FD0F8}") - PROGID = "Dscbo1.CpSvr8561.1" - - -class CpSvr8561T(IDib, IDibEvents): - CLSID = IID("{B76AB425-5D82-4A74-BE0F-B5FAC0453787}") - PROGID = "Dscbo1.CpSvr8561T.1" - - -class CpSvr8562(IDib, IDibEvents): - CLSID = IID("{BCBE0F92-D5A0-44CF-ACB1-572E5246F4C3}") - PROGID = "Dscbo1.CpSvr8562.1" - - -class CpSvr8563(IDib, IDibEvents): - CLSID = IID("{B40008F5-BE02-42D1-AF05-0A95713D9F5C}") - PROGID = "Dscbo1.CpSvr8563.1" - - -class CpSvr8091(IDib, IDibEvents): - CLSID = IID("{2A04F706-DFCD-4588-9130-CCBC2C6043C8}") - PROGID = "Dscbo1.CpSvr8091.1" - - -class CpSvr8091S(IDib, IDibEvents): - CLSID = IID("{FA8F5A92-82B3-45A5-957B-F052EDCE3556}") - PROGID = "Dscbo1.CpSvr8091S.1" - - -class SoptionWeek(IDib, IDibEvents): - CLSID = IID("{0D6CDFB5-78EF-472B-807E-6C994FE01830}") - PROGID = "Dscbo1.SoptionWeek.1" - - -class SoptionMst(IDib, IDibEvents): - CLSID = IID("{DEFA472E-99E2-4355-B2C7-B1894541CC3D}") - PROGID = "Dscbo1.SoptionMst.1" - - -class SoptionCur(IDib, IDibEvents): - CLSID = IID("{CB5D1FFE-52B0-415F-9D97-DF8261878A1A}") - PROGID = "Dscbo1.SoptionCur.1" - - -class SoptionBid(IDib, IDibEvents): - CLSID = IID("{B17A779E-1C22-46B9-81C9-F52A92DCBAA2}") - PROGID = "Dscbo1.SoptionBid.1" - - -class SoptionCallput(IDib, IDibEvents): - CLSID = IID("{1D98FA00-46A7-410D-BEEE-378BE2F232B4}") - PROGID = "Dscbo1.SoptionCallput.1" - - -class CpSvr8081(IDib, IDibEvents): - CLSID = IID("{9D163A76-6432-46D8-AC7E-0F998B7AE283}") - PROGID = "Dscbo1.CpSvr8081.1" - - -class CpSvr8082(IDib, IDibEvents): - CLSID = IID("{C375F210-E366-4CB4-9AE2-60D77D306FCF}") - PROGID = "Dscbo1.CpSvr8082.1" - - -class CpSvr8083(IDib, IDibEvents): - CLSID = IID("{46570098-CA2D-4CCE-A9B0-348728C96814}") - PROGID = "Dscbo1.CpSvr8083.1" - - -class CpSvr8111(IDib, IDibEvents): - CLSID = IID("{4BDD0A5C-CBD7-426A-A1B0-CD7BB6DA3EF7}") - PROGID = "Dscbo1.CpSvr8111.1" - - -class CpSvr8111S(IDib, IDibEvents): - CLSID = IID("{2D79A13E-79DA-41A2-B565-BD9AED15E84B}") - PROGID = "Dscbo1.CpSvr8111S.1" - - -class CpSvr8111KS(IDib, IDibEvents): - CLSID = IID("{91E94973-C856-4368-9402-E1707CE2146C}") - PROGID = "Dscbo1.CpSvr8111KS.1" - - -class CpSvr8116(IDib, IDibEvents): - CLSID = IID("{F17A78B1-7DE3-48AC-AB79-588869083989}") - PROGID = "Dscbo1.CpSvr8116.1" - - -class CpSvr7818(IDib, IDibEvents): - CLSID = IID("{757B16A4-9A6A-427D-9332-BD5ABBAA3083}") - PROGID = "Dscbo1.CpSvr7818.1" - - -class CpSvr7818C(IDib, IDibEvents): - CLSID = IID("{18457BCD-7EC0-4312-9245-0036DC2DDACE}") - PROGID = "Dscbo1.CpSvr7818C.1" - - -class CpSvr7819(IDib, IDibEvents): - CLSID = IID("{C2DCC501-49E9-4ADB-8353-294FE25E7428}") - PROGID = "Dscbo1.CpSvr7819.1" - - -class CpSvr7819C(IDib, IDibEvents): - CLSID = IID("{1481AECC-DCC7-4161-9829-91DFDD24E70B}") - PROGID = "Dscbo1.CpSvr7819C.1" - - -class CpSvr8300(IDib, IDibEvents): - CLSID = IID("{C517AF9D-F297-449F-BECA-7B59F1DB845B}") - PROGID = "Dscbo1.CpSvr8300.1" - - -class CpFore8311(IDib, IDibEvents): - CLSID = IID("{0049522C-26C0-4BCC-AB77-E7AEAD1A4620}") - PROGID = "Dscbo1.CpFore8311.1" - - -class CpFore8312(IDib, IDibEvents): - CLSID = IID("{C192C148-EDC1-400C-ADE8-48778BE42737}") - PROGID = "Dscbo1.CpFore8312.1" - - -class StockMst2(IDib, IDibEvents): - CLSID = IID("{EEA6A7D7-1E8C-4D90-8ACB-7BD391694978}") - PROGID = "Dscbo1.StockMst2.1" - - -class StockOutMst(IDib, IDibEvents): - CLSID = IID("{1D5575F8-D57A-443E-80E8-F2A26F8FC168}") - PROGID = "Dscbo1.StockOutMst.1" - - -class StockOutCur(IDib, IDibEvents): - CLSID = IID("{A58788CC-6F6D-4287-8194-D1D5EBFC13CE}") - PROGID = "Dscbo1.StockOutCur.1" - - -class OptionAtm(IDib, IDibEvents): - CLSID = IID("{7163F981-6552-49E9-84AF-EC1E62FEC867}") - PROGID = "Dscbo1.OptionAtm.1" - - -class FutureOptionStat(IDib, IDibEvents): - CLSID = IID("{76F545B3-CAD9-4474-BA39-F67352924174}") - PROGID = "Dscbo1.FutureOptionStat.1" - - -class FutureOptionStatPB(IDib, IDibEvents): - CLSID = IID("{2079F79D-798E-4C4D-9A0E-7BAC8FE294C3}") - PROGID = "Dscbo1.FutureOptionStatPB.1" - - -class StockIndexiChart(IDib, IDibEvents): - CLSID = IID("{3116500C-0DC1-4C63-B760-043903A463C5}") - PROGID = "Dscbo1.StockIndexiChart.1" - - -class FutOptRest(IDib, IDibEvents): - CLSID = IID("{4FF1F71F-0D95-46F1-80D2-C62E50D46995}") - PROGID = "Dscbo1.FutOptRest.1" - - -class ExpectIndexR(IDib, IDibEvents): - CLSID = IID("{A2570BF0-8BF3-4AB8-A4B9-200741A16A11}") - PROGID = "Dscbo1.ExpectIndexR.1" - - -class ExpectIndexS(IDib, IDibEvents): - CLSID = IID("{484427BE-E0C6-45DD-9368-DEF8DB3EFC9D}") - PROGID = "Dscbo1.ExpectIndexS.1" - - -class FutureCurOnly(IDib, IDibEvents): - CLSID = IID("{21123F9D-FFFC-49B2-ACC1-B89B4EE50A18}") - PROGID = "Dscbo1.FutureCurOnly.1" - - -class CpSvrNew8300(IDib, IDibEvents): - CLSID = IID("{35E4CB92-E022-4905-B006-519345316A80}") - - -class CmeConclusionRt(IDib, IDibEvents): - CLSID = IID("{DC9ECD73-16FE-4AA3-BEC9-2A8D1E9A8B72}") - PROGID = "DsCbo1.CmeConclusionRt.1" - - -class EurexConclusionRt(IDib, IDibEvents): - CLSID = IID("{06CD6CE2-CC6E-46A3-B1DF-FB51DEA97A77}") - PROGID = "DsCbo1.EurexConclusionRt.1" - - -class OptionCallput2(IDib, IDibEvents): - CLSID = IID("{E530DD89-64A2-4DA4-BA1D-546A68BDD193}") - PROGID = "Dscbo1.OptionCallput2.1" - - -class CpSvr8119(IDib, IDibEvents): - CLSID = IID("{5D1F4780-250E-4D0D-873D-2D059454F5F1}") - PROGID = "Dscbo1.CpSvr8119.1" - - -class CpSvr8412(IDib, IDibEvents): - CLSID = IID("{E1017E1F-F779-4624-88FD-97381687E54F}") - PROGID = "Dscbo1.CpSvr8412.1" - - -class CpSvrNew8119(IDib, IDibEvents): - CLSID = IID("{8113D43D-FCCB-4521-A13D-B7CCA8EBF378}") - PROGID = "Dscbo1.CpSvrNew8119.1" - - -class CpSvrNew8119Chart(IDib, IDibEvents): - CLSID = IID("{FD0CCD4E-3E44-4288-A42C-606D9703373B}") - PROGID = "Dscbo1.CpSvrNew8119Chart.1" - - -class CpSvr7244(IDib, IDibEvents): - CLSID = IID("{F5075466-0FB5-45CC-85AA-D902F1D173C3}") - PROGID = "DsCbo1.CpSvr7244.1" - - -class CpSvr7246(IDib, IDibEvents): - CLSID = IID("{8CE1E3A6-F42C-4959-B747-287A06921D4A}") - PROGID = "DsCbo1.CpSvr7246.1" - - -class CpSvr7718(IDib, IDibEvents): - CLSID = IID("{5E64D7D7-D393-4326-95AD-3FCBA4A4BF46}") - PROGID = "DsCbo1.CpSvr7718.1" - - -class CpSvr7719(IDib, IDibEvents): - CLSID = IID("{8B4FF082-FB67-4A38-868B-B1583D0C5AD2}") - PROGID = "DsCbo1.CpSvr7719.1" - - -class CpSvrNew8119Day(IDib, IDibEvents): - CLSID = IID("{6F491767-5800-4E11-B454-E3270FCBBD17}") - PROGID = "DsCbo1.CpSvrNew8119Day.1" - - -class CpSvr9027(IDib, IDibEvents): - CLSID = IID("{55896A25-A1DF-4BBA-96BD-9598EF5AD9D6}") - PROGID = "DsCbo1.CpSvr9027.1" - - -class UpjongDaily(IDib, IDibEvents): - CLSID = IID("{3B532417-7AE8-4434-84F2-814AB8D6435B}") - PROGID = "DsCbo1.UpjongDaily.1" diff --git a/koapy/backend/daishin_cybos_plus/stub/__init__.py b/koapy/backend/daishin_cybos_plus/stub/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/tools/__init__.py b/koapy/backend/daishin_cybos_plus/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/daishin_cybos_plus/tools/generate_python_stubs.py b/koapy/backend/daishin_cybos_plus/tools/generate_python_stubs.py deleted file mode 100644 index fc91cdc5..00000000 --- a/koapy/backend/daishin_cybos_plus/tools/generate_python_stubs.py +++ /dev/null @@ -1,43 +0,0 @@ -import ast - -from pathlib import Path - -try: - from ast import unparse -except ImportError: - from astunparse import unparse - -from koapy.backend.daishin_cybos_plus.core.CybosPlusTypeLibSpec import ( - CPFOREDIB_CLSID, - CPFORETRADE_CLSID, - CPSYSDIB_CLSID, - CPTRADE_CLSID, - CPUTIL_CLSID, - DSCBO1_CLSID, -) -from koapy.common.StubGenerator import make_stub_module - - -def main(): - script_dir = Path(__file__).parent - stub_dir = script_dir / ".." / "stub" - modules = { - "CpForeDib": CPFOREDIB_CLSID, - "CpForeTrade": CPFORETRADE_CLSID, - "CpSysDib": CPSYSDIB_CLSID, - "CpTrade": CPTRADE_CLSID, - "CpUtil": CPUTIL_CLSID, - "DsCbo1": DSCBO1_CLSID, - } - for name, clsid in modules.items(): - stub_filename = f"{name}.py" - stub_filepath = stub_dir / stub_filename - mod = make_stub_module(clsid) - mod = ast.fix_missing_locations(mod) - code = unparse(mod) - with open(stub_filepath, "w", encoding="utf-8") as f: - f.write(code) - - -if __name__ == "__main__": - main() diff --git a/koapy/backend/kiwoom_open_api_plus/__init__.py b/koapy/backend/kiwoom_open_api_plus/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.py deleted file mode 100644 index 3058d118..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition.py +++ /dev/null @@ -1,213 +0,0 @@ -import contextlib - -from os import PathLike -from pathlib import Path -from typing import Optional, Sequence, TextIO, Union - - -class KiwoomOpenApiPlusConditionEntry: - def __init__( - self, - header, - item_id, - group_id, - group_name, - group_tp, - name, - group_id_small, - order_no, - type_position, - upjong, - portfolio, - recommend, - acc, - group, - excepts, - month, - exp, - count, - rules, - ): - self.header = header - self.item_id = item_id - self.group_id = group_id - self.group_name = group_name - self.group_tp = group_tp - self.name = name - self.group_id_small = group_id_small - self.order_no = order_no - self.type_position = type_position - self.upjong = upjong - self.portfolio = portfolio - self.recommend = recommend - self.acc = acc - self.group = group - self.excepts = excepts - self.month = month - self.exp = exp - self.count = count - self.rules = rules - - def __repr__(self): - template = "{}" + "({})".format(", ".join(["{!r}" for _ in range(19)])) - return template.format( - self.__class__.__name__, - self.header, - self.item_id, - self.group_id, - self.group_name, - self.group_tp, - self.name, - self.group_id_small, - self.order_no, - self.type_position, - self.upjong, - self.portfolio, - self.recommend, - self.acc, - self.group, - self.excepts, - self.month, - self.exp, - self.count, - self.rules, - ) - - @classmethod - def from_datfile(cls, f: TextIO): - lines = iter(f) - lines = map(lambda line: line.rstrip("\n"), lines) - line = next(lines) - while line == "": - line = next(lines) - assert line.startswith("[") and line.endswith("]") - header = line - line = next(lines) - assert line.startswith("ItemID=") - item_id = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("GroupID=") - group_id = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("GroupName=") - group_name = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("GroupTp=") - group_tp = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Name=") - name = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("GroupId=") - group_id_small = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("OrderNo=") - order_no = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("TypePosition=") - type_position = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Upjong=") - upjong = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Portfolio=") - portfolio = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Recommend=") - recommend = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Acc=") - acc = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Group=") - group = line.split("=", 2)[1] - excepts = [] - for i in range(22): - line = next(lines) - assert line.startswith(f"Except{i+1}=") - except_item = line.split("=", 2)[1] - excepts.append(except_item) - line = next(lines) - assert line.startswith("Month=") - month = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Exp=") - exp = line.split("=", 2)[1] - line = next(lines) - assert line.startswith("Count=") - count = line.split("=", 2)[1] - count = int(count) - rules = [] - for i in range(count): - line = next(lines) - assert line.startswith(f"{str(i).zfill(2)}=") - rule_num, rule_expr = line.split("=", 2) - rule = (rule_num, rule_expr) - rules.append(rule) - return cls( - header, - item_id, - group_id, - group_name, - group_tp, - name, - group_id_small, - order_no, - type_position, - upjong, - portfolio, - recommend, - acc, - group, - excepts, - month, - exp, - count, - rules, - ) - - -class KiwoomOpenApiPlusConditionFile: - def __init__( - self, version: str, entries: Sequence[KiwoomOpenApiPlusConditionEntry] - ): - self.version = version - self.entries = list(entries) - - def __repr__(self): - template = "{}" + "({})".format(", ".join(["{!r}" for _ in range(2)])) - return template.format( - self.__class__.__name__, - self.version, - self.entries, - ) - - @classmethod - def from_datfile( - cls, f: Union[str, PathLike, TextIO], encoding: Optional[str] = None - ): - if isinstance(f, str): - f = Path(f) - if encoding is None: - encoding = "euc-kr" - with contextlib.ExitStack() as stack: - if isinstance(f, PathLike): - f = open(f, "r", encoding=encoding) - f = stack.enter_context(f) - lines = iter(f) - lines = map(lambda line: line.rstrip("\n"), lines) - line = next(lines) - assert line == "[Version]" - line = next(lines) - assert line.startswith("ver=") - version = line.split("=", 2)[1] - entries = [] - should_stop = False - while not should_stop: - try: - cond = KiwoomOpenApiPlusConditionEntry.from_datfile(f) - except StopIteration: - break - else: - entries.append(cond) - return cls(version, entries) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.py deleted file mode 100644 index 4d03f725..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions.py +++ /dev/null @@ -1,1251 +0,0 @@ -# pylint: disable=unused-argument,unnecessary-ellipsis - - -class KiwoomOpenApiPlusDispatchFunctions: - def CommConnect(self) -> int: - """ - 로그인 윈도우를 실행한다. - - 수동 로그인 설정인 경우 로그인창을 출력. - 자동 로그인 설정인 경우 로그인창에서 자동으로 로그인을 시도합니다. - - 로그인이 성공하거나 실패하는 경우 OnEventConnect() 이벤트가 발생하고 이벤트의 - 인자 값으로 로그인 성공 여부를 알 수 있다. - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def CommTerminate(self) -> None: - """ - 더 이상 지원하지 않는 함수. - - 프로그램 종료없이 서버와의 접속만 단절시키는 함수입니다. - ※ 함수 사용 후 사용자의 오해소지가 생기는 이유로 더 이상 사용할 수 없는 함수입니다. - - 통신 연결 상태는 GetConnectState() 메소드로 알 수 있다. - """ - ... - - def CommRqData( - self, sRQName: str, sTrCode: str, nPrevNext: int, sScreenNo: str - ) -> int: - """ - 통신 데이터를 서버로 전송한다. - - 반환 코드 구분: - - OP_ERR_NONE(0): 정상처리 - - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 - - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 - - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 - - Args: - sRQName (str): 사용자 구분명 (임의로 지정, 한글 지원) - sTrCode (str): 조회하려는 TR 코드 - nPrevNext (int): 연속조회 여부 (0:조회, 2:연속) - sScreenNo (str): 화면번호 (4자리 숫자 임의로 지정) - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def GetLoginInfo(self, sTag: str) -> str: - """ - 로그인한 사용자 정보를 반환한다. - - 태그값 구분: - - "ACCOUNT_CNT": 전체 보유계좌 개수를 반환합니다. - - "ACCLIST" 또는 "ACCNO": 구분자 ';' 로 연결된 전체 보유계좌 목록을 반환합니다. - - "USER_ID": 사용자 ID를 반환합니다. - - "USER_NAME": 사용자 이름을 반환합니다. - - "KEY_BSECGB": 키보드 보안 해지 여부를 반환합니다. (0:정상, 1:해지) - - "FIREW_SECGB": 방화벽 설정 여부를 반환합니다. (0:미설정, 1:설정, 2:해지) - - "GetServerGubun": 접속서버 구분을 반환합니다. (1:모의투자, 나머지:실거래서버) - - Args: - sTag (str): 사용자 정보 구분 태그 값 - - Returns: - str: 태그값에 따른 데이터 반환 - """ - ... - - def SendOrder( - self, - sRQName: str, - sScreenNo: str, - sAccNo: str, - nOrderType: int, - sCode: str, - nQty: int, - nPrice: int, - sHogaGb: str, - sOrgOrderNo: str, - ) -> int: - """ - 주식 주문을 서버로 전송한다. - - 서버에 주문을 전송하는 함수 입니다. - 9개 인자값을 가진 주식주문 함수이며 리턴값이 0이면 성공이며 나머지는 에러입니다. - 1초에 5회만 주문가능하며 그 이상 주문요청하면 에러 -308을 리턴합니다. - - ※ 시장가, 최유리지정가, 최우선지정가, 시장가IOC, 최유리IOC, 시장가FOK, 최유리FOK, 장전시간외, 장후시간외 주문시 주문가격은 0으로 입력합니다. - ※ 취소 주문일때 주문가격은 0으로 입력합니다. - - 거래 구분: - - 00: 지정가 - - 03: 시장가 - - 05: 조건부지정가 - - 06: 최유리지정가 - - 07: 최우선지정가 - - 10: 지정가IOC - - 13: 시장가IOC - - 16: 최유리IOC - - 20: 지정가FOK - - 23: 시장가FOK - - 26: 최유리FOK - - 61: 장전시간외종가 - - 62: 시간외단일가매매 - - 81: 장후시간외종가 - - ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. - - 정규장 외 주문: - - 장전 동시호가 주문 - - 08:30 ~ 09:00. 거래구분 00:지정가/03:시장가 (일반주문처럼) - - ※ 08:20 ~ 08:30 시간의 주문은 키움에서 대기하여 08:30 에 순서대로 거래소로 전송합니다. - - 장전시간외 종가 - - 08:30 ~ 08:40. 거래구분 61:장전시간외종가. 가격 0입력 - - ※ 전일 종가로 거래. 미체결시 자동취소되지 않음 - - 장마감 동시호가 주문 - - 15:20 ~ 15:30. 거래구분 00:지정가/03:시장가 (일반주문처럼) - - 장후 시간외 종가 - - 15:40 ~ 16:00. 거래구분 81:장후시간외종가. 가격 0입력 - - ※ 당일 종가로 거래 - - 시간외 단일가 - - 16:00 ~ 18:00. 거래구분 62:시간외단일가. 가격 입력 - - ※ 10분 단위로 체결, 당일 종가대비 +-10% 가격으로 거래 - - 주문 유형: - - 1: 신규매수 - - 2: 신규매도 - - 3: 매수취소 - - 4: 매도취소 - - 5: 매수정정 - - 6: 매도정정 - - Args: - sRQName (str): 사용자 구분 요청명 - sScreenNo (str): 화면번호 (4자리) - sAccNo (str): 계좌번호 (10자리) - nOrderType (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) - sCode (str): 종목코드 (6자리) - nQty (int): 주문수량 - nPrice (int): 주문단가 - sHogaGb (str): 거래구분 (혹은 호가구분) - sOrgOrderNo (str): 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def SendOrderFO( - self, - sRQName: str, - sScreenNo: str, - sAccNo: str, - sCode: str, - lOrdKind: int, - sSlbyTp: str, - sOrdTp: str, - lQty: int, - sPrice: str, - sOrgOrdNo: str, - ) -> int: - """ - 선물/옵션 주문을 서버로 전송한다. - - 서버에 주문을 전송하는 함수 입니다. - 코스피지수200 선물옵션 전용 주문함수입니다. - - 거래 구분: - - 1: 지정가 - - 2: 조건부지정가 - - 3: 시장가 - - 4: 최유리지정가 - - 5: 지정가(IOC) - - 6: 지정가(FOK) - - 7: 시장가(IOC) - - 8: 시장가(FOK) - - 9: 최유리지정가(IOC) - - A: 최유리지정가(FOK) - - ※ 장종료 후 시간외 주문은 지정가 선택 - - Args: - sRQName (str): 사용자 구분명 - sScreenNo (str): 화면번호 - sAccNo (str): 계좌번호 (10자리) - sCode (str): 종목코드 - lOrdKind (int): 주문종류 (1:신규매매, 2:정정, 3:취소) - sSlbyTp (str): 매매구분 (1:매도, 2:매수) - sOrdTp (str): 거래구분 - lQty (int): 주문수량 - sPrice (str): 주문가격 - sOrgOrdNo (str): 원주문번호 - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def SetInputValue(self, sID: str, sValue: str) -> None: - """ - TR 입력 값을 서버통신 전에 입력한다. - - 조회요청시 TR의 Input값을 지정하는 함수입니다. - CommRqData() 호출 전에 입력값들을 셋팅합니다. - 각 TR마다 Input 항목이 다릅니다. 순서에 맞게 Input 값들을 셋팅해야 합니다. - - Args: - sID (str): TR에 명시된 Input 이름 - sValue (str): Input 이름으로 지정한 값 - """ - ... - - def SetOutputFID(self, sID: str) -> int: - """ - 1.0.0.1 버전 이후 사용하지 않음. - """ - ... - - def CommGetData( - self, - sJongmokCode: str, - sRealType: str, - sFieldName: str, - nIndex: int, - sInnerFieldName: str, - ) -> str: - """ - 이 함수는 지원하지 않을 것이므로 용도에 맞는 전용 함수를 사용할 것. (비고참고) - - 일부 TR에서 사용상 제약이 있으므로 이 함수 대신 GetCommData() 함수를 사용하시기 바랍니다. - - 비고: - - 조회 정보 요청: GetCommData(strTrCode: str, strRecordName: str, nIndex: int, strItemName: str) - - 실시간 정보 요청: GetCommRealData(sTrCode: str, nFid: int) - - 체결 정보 요청: GetChejanData(nFid: int) - """ - ... - - def DisconnectRealData(self, sScnNo: str) -> None: - """ - 화면 내 모든 리얼데이터 요청을 제거한다. - - 시세데이터를 요청할때 사용된 화면번호를 이용하여 - 해당 화면번호로 등록되어져 있는 종목의 실시간시세를 서버에 등록해지 요청합니다. - 이후 해당 종목의 실시간시세는 수신되지 않습니다. - 단, 해당 종목이 또다른 화면번호로 실시간 등록되어 있는 경우 해당종목에대한 실시간시세 데이터는 계속 수신됩니다. - - 화면을 종료할 때 반드시 위 함수를 호출해야 한다. - - Args: - sScnNo: 화면번호 (4자리) - """ - ... - - def GetRepeatCnt(self, sTrCode: str, sRecordName: str) -> int: - """ - 레코드 반복횟수를 반환한다. - - 데이터 수신시 멀티데이터의 갯수(반복수)를 얻을수 있습니다. - 예를 들어 차트조회는 한번에 최대 900개 데이터를 수신할 수 있는데 - 이렇게 수신한 데이터갯수를 얻을때 사용합니다. - 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. - - Args: - sTrCode (str): TR 이름 - sRecordName (str): 레코드 이름 - - Returns: - int: 레코드의 반복횟수 - """ - ... - - def CommKwRqData( - self, - sArrCode: str, - bNext: int, - nCodeCount: int, - nTypeFlag: int, - sRQName: str, - sScreenNo: str, - ) -> int: - """ - 복수종목조회 요청을 서버로 송신한다. - - 한번에 100종목까지 조회할 수 있는 복수종목 조회함수 입니다. - 함수인자로 사용하는 종목코드 리스트는 조회하려는 종목코드 사이에 구분자 ';' 를 추가해서 만들면 됩니다. - 수신되는 데이터는 TR목록에서 복수종목정보요청(OPTKWFID) Output을 참고하시면 됩니다. - - ※ OPTKWFID TR은 CommKwRqData() 함수 전용으로, CommRqData 로는 사용할 수 없습니다. - ※ OPTKWFID TR은 영웅문4 HTS의 관심종목과는 무관합니다. - - 반환 코드 구분: - - OP_ERR_NONE(0): 정상처리 - - OP_ERR_SISE_OVERFLOW(-200): 과도한 시세조회로 인한 통신불가 - - OP_ERR_RQ_STRUCT_FAIL(-201): 입력 구조체 생성 실패 - - OP_ERR_RQ_STRING_FAIL(-202): 요청전문 작성 실패 - - Args: - sArrCode (str): 종목리스트 - bNext (int): 연속조회 여부 (0:기본값, 1:연속조회(지원안함)) - nCodeCount (int): 종목개수 - nTypeFlag (int): 조회구분 (0:주식 종목, 3:선물옵션 종목) - sRQName (str): 사용자 구분명 - sScreenNo (str): 화면번호 (4자리) - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def GetAPIModulePath(self) -> str: - """ - OpenAPI 모듈의 경로를 반환한다. - - Returns: - str: OpenAPI 모듈의 설치 경로 - """ - ... - - def GetCodeListByMarket(self, sMarket: str) -> str: - """ - 시장구분에 따른 종목코드를 반환한다. - - 주식 시장별 종목코드 리스트를 ';' 로 구분해서 전달합니다. - 시장구분값을 "" 공백으로 하면 전체시장 코드리스트를 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - 시장 구분: - - 0: 장내 - - 3: ELW - - 4: 뮤추얼펀드 - - 5: 신주인수권 - - 6: 리츠 - - 8: ETF - - 9: 하이일드펀드 - - 10: 코스닥 - - 30: K-OTC - - 50: 코넥스 (KONEX) - - Args: - sMarket (str): 시장 구분값 - - Returns: - str: 종목코드 리스트, 종목간 구분은 ';' 이다. - """ - ... - - def GetConnectState(self) -> int: - """ - 현재 접속상태를 반환한다. - - 서버와 현재 접속 상태를 알려줍니다. - - Returns: - int: 접속상태, 1:연결, 0:연결안됨 - """ - ... - - def GetMasterCodeName(self, sTrCode: str) -> str: - """ - 종목코드의 한글명을 반환한다. - - 종목코드에 해당하는 종목명을 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - 장내외, 지수선옵, 주식선옵 검색 가능. - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - str: 종목 한글명 - """ - ... - - def GetMasterListedStockCnt(self, sTrCode: str) -> int: - """ - 종목코드의 상장주식수를 반환한다. - - 입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - int: 상장주식수 - """ - ... - - def GetMasterConstruction(self, sTrCode: str) -> str: - """ - 종목코드의 감리구분을 반환한다. - - 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. - (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) - - 로그인 한 후에 사용할 수 있는 함수입니다. - - 감리 구분: - - 정상 - - 투자주의 - - 투자경고 - - 투자위험 - - 투자주의환기종목 - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - str: 감리구분 (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) - """ - ... - - def GetMasterListedStockDate(self, sTrCode: str) -> str: - """ - 종목코드의 상장일을 반환한다. - - 입력한 종목의 상장일을 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - str: 상장일 (8자리, YYYYMMDD) - """ - ... - - def GetMasterLastPrice(self, sTrCode: str) -> str: - """ - 종목코드의 전일가를 반환한다. - - 입력한 종목의 당일 기준가를 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - str: 전일가 - """ - ... - - def GetMasterStockState(self, sTrCode: str) -> str: - """ - 종목코드의 종목상태를 반환한다. - - 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - Args: - sTrCode (str): 종목코드 (4자리) - - Returns: - str: 종목상태 (정상, 증거금N%, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능) - """ - ... - - def GetDataCount(self, strRecordName: str) -> int: - """ - 레코드의 반복개수를 반환한다. - - ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 - 해당 함수 대신 GetRepeatCnt() 를 사용하는게 더 바람직할 듯 - - Args: - strRecordName (str): 레코드 명 - - Returns: - str: 레코드 반복개수 - """ - ... - - def GetOutputValue(self, strRecordName: str, nRepeatIdx: int, nItemIdx: int) -> str: - """ - 레코드의 반복순서와 아이템의 출력순서에 따라 수신데이터를 반환한다. - - ※ 문서상으로만 존재하고 KOAStudio 에서는 확인 안되는 것으로 보아 일반적인 상황에선 - 해당 함수 대신 GetCommData() 를 사용하는게 더 바람직할 듯 - - Args: - strRecordName (str): 레코드 명 - nRepeatIdx (int): 반복 순서 - nItemIdx (int): 아이템 순서 - - Returns: - str: 수신 데이터 - """ - ... - - def GetCommData( - self, strTrCode: str, strRecordName: str, nIndex: int, strItemName: str - ) -> str: - """ - 수신 데이터를 반환한다. - - OnReceiveTRData() 이벤트가 발생될때 수신한 데이터를 얻어오는 함수입니다. - 이 함수는 OnReceiveTRData() 이벤트가 발생될때 그 안에서 사용해야 합니다. - - Args: - strTrCode (str): TR코드 - strRecordName (str): 레코드명 - nIndex (int): 복수데이터 인덱스 - strItemName (str): 아이템명 (TR별 출력항목 이름) - - Returns: - str: 수신 데이터 - """ - ... - - def GetCommRealData(self, sTrCode: str, nFid: int) -> str: - """ - 실시간 시세 데이터를 반환한다. - - 실시간시세 데이터 수신 이벤트인 OnReceiveRealData() 가 발생될때 실시간데이터를 얻어오는 함수입니다. - 이 함수는 OnReceiveRealData() 이벤트가 발생될때 그 안에서 사용해야 합니다. - FID 값은 KOAStudio 의 "실시간목록" 탭에서 확인할 수 있습니다. - - 일반적으로 strTrCode 는 OnReceiveRealData() 이벤트 함수의 첫번째 매개변수를 사용한다. - - Args: - strTrCode (str): TR코드 - nFid (int): 실시간 아이템 - - Returns: - str: 수신 데이터 - """ - ... - - def GetChejanData(self, nFid: int) -> str: - """ - 체결잔고 데이터를 반환한다. - - OnReceiveChejan() 이벤트가 발생될때 FID 에 해당되는 값을 구하는 함수입니다. - 이 함수는 OnReceiveChejan() 이벤트 안에서 사용해야 합니다. - Ex) 체결가 = GetChejanData(910) - - Args: - nFid (int): 체결잔고 아이템 - - Returns: - str: 수신 데이터 - """ - ... - - def GetThemeGroupList(self, nType: int) -> str: - """ - 테마코드와 테마명을 반환한다. - - 반환값의 코드와 코드명 구분은 '|', 코드의 구분은 ';' - Ex) 100|태양광_폴리실리콘;152|합성섬유 - - Args: - nType (int): 정렬순서 (0:코드순, 1:테마순) - - Returns: - str: 코드와 코드명 리스트 - """ - ... - - def GetThemeGroupCode(self, strThemeCode: str) -> str: - """ - 테마코드에 소속된 종목코드를 반환한다. - - 반환값의 종목코드간 구분은 ';' - Ex) A000660;A005930 - - Args: - strThemeCode (str): 테마코드 - - Returns: - str: 종목코드 리스트 - """ - ... - - def GetFutureList(self) -> str: - """ - 지수선물 리스트를 반환한다. - - 지수선물 종목코드 리스트를 ';'로 구분해서 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - 반환값의 종목코드간 구분은 ';' - Ex) 101J9000;101JC000 - - Returns: - str: 종목코드 리스트 - """ - ... - - def GetFutureCodeByIndex(self, nIndex: int) -> str: - """ - 지수선물 코드를 반환한다. - - Ex) 최근월선물 = GetFutureCodeByIndex(0) - 최근월스프레드 = GetFutureCodeByIndex(4) - - Args: - nIndex (int): 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드 - - Returns: - str: 종목코드 - """ - ... - - def GetActPriceList(self) -> str: - """ - 지수옵션 행사가 리스트를 반환한다. - - 지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ';' 로 구분해서 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - ※ PDF 문서상의 예시에서는 소수점 아래가 존재하는 예시지만, KOAStudio 의 설명과 예시에서는 그렇지 않음. - 아마도 KOAStudio 의 설명을 따르는게 더 바람직할 듯. - - Returns: - str: 행사가 - """ - ... - - def GetMonthList(self) -> str: - """ - 지수옵션 월물 리스트를 반환한다. - - 지수옵션 월물정보를 ';' 로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - 반환값의 월물간 구분은 ';' - Ex) 201412;201409;201408;201407;201407;201408;201409;201412 - - Returns: - str: 월물 (YYYYMM;YYYYMM;...) - """ - ... - - def GetOptionCode(self, strActPrice: str, nCp: int, strMonth: str) -> str: - """ - 행사가와 월물 콜풋으로 종목코드를 구한다. - - 인자로 지정한 지수옵션 코드를 전달합니다. - - 로그인 한 후에 사용할 수 있는 함수입니다. - - Args: - strActPrice (str): 행사가 (소수점 포함) - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - strMonth (str): 월물 (6자리, YYYYMM) - - Returns: - str: 종목코드 - - Examples: - >>> GetOptionCode("260.00", 2, "201407") - """ - ... - - def GetOptionCodeByMonth(self, sTrCode: str, nCp: int, strMonth: str) -> str: - """ - 입력된 종목코드와 동일한 행사가의 코드중 입력한 월물의 코드를 구한다. - - Args: - sTrCode (str): 종목코드 - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - strMonth (str): 월물 (6자리, YYYYMM) - - Returns: - str: 종목코드 - - Examples: - >>> GetOptionCodeByMonth("201J7260", 2, "201412") - "201JC260" - """ - ... - - def GetOptionCodeByActPrice(self, sTrCode: str, nCp: int, nTick: int) -> str: - """ - 입력된 종목코드와 동일한 월물의 코드중 입력한 틱만큼 벌어진 코드를 구한다. - - Args: - sTrCode (str): 종목코드 - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - nTick (int): 행사가 틱 - - Returns: - str: 종목코드 - - Examples: - >>> GetOptionCodeByActPrice("201J7260", 2, -1) - "201J7262" - """ - ... - - def GetSFutureList(self, strBaseAssetCode: str) -> str: - """ - 주식선물 코드 리스트를 반환한다. - - 출력값의 코드간 구분은 ';' 이다. - - Args: - strBaseAssetCode (str): 기초자산코드 - - Return: - str: 종목코드 리스트 - """ - ... - - def GetSFutureCodeByIndex(self, strBaseAssetCode: str, nIndex: int) -> str: - """ - 주식선물 코드를 반환한다. - - Args: - strBaseAssetCode (str): 기초자산코드 - nIndex (int): 0 ~ 3: 지수선물코드, 4 ~ 7: 지수스프레드, 8 ~ 11: 스타 선물, 12 ~ : 스타 스프레드 - - Return: - str: 종목코드 리스트 - - Examples: - >>> GetSFutureCodeByIndex("11", 0) - """ - ... - - def GetSActPriceList(self, strBaseAssetGb: str) -> str: - """ - 주식옵션 행사가 리스트를 반환한다. - - Args: - strBaseAssetGb (str): 기초자산코드구분 - - Return: - str: 행사가 리스트, 행사가간 구분은 ';' - - Examples: - >>> GetSActPriceList("11") - """ - ... - - def GetSMonthList(self, strBaseAssetGb: str) -> str: - """ - 주식옵션 월물 리스트를 반환한다. - - Args: - strBaseAssetGb (str): 기초자산코드구분 - - Return: - str: 월물 리스트, 월물간 구분은 ';' - - Examples: - >>> GetSMonthList("11") - """ - ... - - def GetSOptionCode( - self, strBaseAssetGb: str, strActPrice: str, nCp: int, strMonth: str - ) -> str: - """ - 주식옵션 코드를 반환한다. - - Args: - strBaseAssetGb (str): 기초자산코드구분 - strActPrice (str): 행사가 (소수점 포함) - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - strMonth (str): 월물 (6자리, YYYYMM) - - Returns: - str: 주식옵션 코드 - - Examples: - >>> GetSOptionCode("11", "1300000", 2, "1412") - """ - ... - - def GetSOptionCodeByMonth( - self, strBaseAssetGb: str, sTrCode: str, nCp: int, strMonth: str - ) -> str: - """ - 입력한 주식옵션 코드에서 월물만 변경하여 반환한다. - - Args: - strBaseAssetGb (str): 기초자산코드구분 - sTrCode (str): 종목코드 - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - strMonth (str): 월물 (6자리, YYYYMM) - - Returns: - str: 주식옵션 코드 - - Examples: - >>> GetSOptionCodeByMonth("11", "211J8045", 2, "1412") - """ - ... - - def GetSOptionCodeByActPrice( - self, strBaseAssetGb: str, sTrCode: str, nCp: int, nTick: int - ) -> str: - """ - 입력한 주식옵션 코드에서 행사가만 변경하여 반환한다. - - Args: - strBaseAssetGb (str): 기초자산코드구분 - sTrCode (str): 종목코드 - nCp (int): 콜/풋 구분 (2:콜, 3:풋) - nTick (int): 행사가 틱 - - Returns: - str: 주식옵션 코드 - - Examples: - >>> GetSOptionCodeByActPrice("11", "211J8045", 2, 4); - """ - ... - - def GetSFOBasisAssetList(self) -> str: - """ - 주식선옵 기초자산코드/종목명을 반환한다. - - Returns: - str: 기초자산코드/종목명, 코드와 종목명 구분은 '|', 코드간 구분은 ';' - """ - ... - - def GetOptionATM(self) -> str: - """ - 지수옵션 ATM을 반환한다. - - Returns: - str: ATM - """ - ... - - def GetSOptionATM(self, strBaseAssetGb: str) -> str: - """ - 주식옵션 ATM을 반환한다. - - Returns: - str: ATM - """ - ... - - def GetBranchCodeName(self) -> str: - """ - 회원사 코드와 이름을 반환합니다. - - Returns: - str: 회원사코드/회원사명, 코드와 이름 구분은 '|', 코드간 구분은 ';' (회원사코드|회원사명;회원사코드|회원사명;...) - """ - ... - - def CommInvestRqData(self, sMarketGb: str, sRQName: str, sScreenNo: str) -> int: - """ - 지원하지 않는 함수. - - 시장 구분: - - 001: 코스피 - - 002: 코스닥 - - 003: 선물 - - 004: 콜옵션 - - 005: 풋옵션 - - 006: 스타선물 - - 007: 주식선물 - - 008: 3년국채 - - 009: 5년국채 - - 010: 10년국채 - - 011: 달러선물 - - 012: 엔선물 - - 013: 유로선물 - - 014: 미니금선물 - - 015: 금선물 - - 016: 돈육선물 - - 017: 달러콜옵션 - - 018: 달러풋옵션 - - Args: - sMarketGb (str): 시장구분 - sRQName (str): 사용자 구분값 - sScreenNo (str): 화면번호 (4자리) - - Returns: - str: 통신결과 - - Examples: - >>> CommInvestRqData("T00108;T00109", 0, 2, "RQ_1", "0101") - """ - ... - - def SendOrderCredit( - self, - sRQName: str, - sScreenNo: str, - sAccNo: str, - nOrderType: int, - sCode: str, - nQty: int, - nPrice: int, - sHogaGb: str, - sCreditGb: str, - sLoanDate: str, - sOrgOrderNo: str, - ) -> int: - """ - 신용주식 주문을 서버로 전송한다. - - 서버에 주문을 전송하는 함수 입니다. - 국내주식 신용주문 전용함수입니다. 대주거래는 지원하지 않습니다. - - 거래 구분: - - 00: 지정가 - - 03: 시장가 - - 05: 조건부지정가 - - 06: 최유리지정가 - - 07: 최우선지정가 - - 10: 지정가IOC - - 13: 시장가IOC - - 16: 최유리IOC - - 20: 지정가FOK - - 23: 시장가FOK - - 26: 최유리FOK - - 61: 장전시간외종가 - - 62: 시간외단일가매매 - - 81: 장후시간외종가 - - ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. - - 신용거래 구분: - - 03: 신용매수 주문 \\- 자기융자 - - 대출일은 공백 입력 - - 33: 신용매도 융자상환 주문 \\- 자기융자 - - 대출일은 종목별 대출일 입력 - - OPW00005/OPW00004 TR조회로 대출일 조회 - - 99: 신용매도 자기융자 합 - - 대출일은 "99991231" 입력 - - 단, 신용잔고 5개 까지만 융자합 주문 가능 - - 대출일은 YYYYMMDD 형식입니다. - 신용매도 - 자기융자 일때는 종목별 대출일을 입력하고 신용매도 - 융자합이면 "99991231"을 입력합니다. - - Args: - sRQName (str): 사용자 구분 요청명 - sScreenNo (str): 화면번호 (4자리) - sAccNo (str): 계좌번호 (10자리) - nOrderType (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) - sCode (str): 종목코드 (6자리) - nQty (int): 주문수량 - nPrice (int): 주문단가 - sHogaGb (str): 거래구분 - sCreditGb (str): 신용구분 - sLoanDate (str): 대출일 (8자리, YYYYMMDD) - sOrgOrderNo (str): 원주문번호 - - Returns: - int: 에러코드, 성공하면 0 을, 실패하면 음수를 반환 - """ - ... - - def KOA_Functions(self, sFunctionName: str, sParam: str) -> str: - """ - OpenAPI 기본 기능 이외의 기능들을 제공하는 헬퍼 함수. - - KOA_Function() 함수는 OpenAPI 기본 기능 이외의 기능을 사용하기 쉽도록 만든 함수입니다. - 두 개의 인자값을 사용합니다. - - 기능 목록: - - 1. 계좌 비밀번호 입력창 출력 - - >>> KOA_Functions("ShowAccountWindow", "") - - 2. 접속 서버 확인 (1:모의투자, 나머지:실서버) - - >>> KOA_Functions("GetServerGubun", "") - - 3. 주식종목 시장구분, 종목분류등 정보제공 (구분자는 '|' 와 ';') - 호출결과는 입력한 종목에 대한 대분류, 중분류, 업종구분값을 구분자로 연결한 문자열입니다. - - >>> KOA_Functions("GetMasterStockInfo", "039490") - "시장구분0|거래소;시장구분1|중형주;업종구분|금융업;" - - 4. 조건검색 종목코드와 현재가 수신 (실시간 조건검색은 사용할 수 없음) - 조건검색결과에 종목코드와 그 종목의 현재가를 함께 수신하는 방법이며 실시간 조건검색에서는 사용할 수 없고 오직 조건검색에만 사용할수 있습니다. - - >>> KOA_Functions("SetConditionSearchFlag", "AddPrice") # 현재가 포함하도록 설정 - - 현재가 포함으로 설정시 OnReceiveTrCondition() 이벤트에 "종목코드1^현재가1;종목코드2^현재가2;...종목코드n^현재가n" 형식으로 전달됨. - - >>> KOA_Functions("SetConditionSearchFlag", "DelPrice") # 현재가 미포함 (원래 상태로 전환) - - 현재가 미포함시 기존처럼 "종목코드1^종목코드2...종목코드n" 형식으로 전달므로 설정에 따라 수신데이터 처리방법이 달라져야 하므로 주의하셔야 합니다. - - 5. 업종코드목록 획득 - - >>> KOA_Functions("GetUpjongCode", "0") - - 두번째 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. - 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 - - 함수반환값은 "시장구분값,업종코드,업종명|시장구분값,업종코드,업종명|...|시장구분값,업종코드,업종명" 형식입니다. - 즉 하나의 업종코드는 입력한 시장구분값과 업종코드 그리고 그 업종명이 쉼표(,)로 구분되며 각 업종코드는 '|'로 구분됩니다. - - 6. 업종이름 획득 - - >>> KOA_Functions("GetUpjongNameByCode", "업종코드입력") - - 7. ETF 투자유의 종목 여부 (2020/09/17 적용) - 거래소 제도개선으로 ETF/ETN 종목 중 투자유의 종목을 매수주문하는 경우 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. - (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) - 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. - - >>> KOA_Functions("IsOrderWarningETF", "종목코드(6자리)") - - 투자유의 종목인 경우 "1" 값이 리턴, 그렇지 않은 경우 "0" 값 리턴. (ETF가 아닌 종목을 입력시 "0" 값 리턴.) - - 8. 주식 전종목대상 투자유의 종목 여부 (2020/11/26 적용) - 거래소 제도개선으로 주식 종목 중 정리매매/단기과열/투자위험/투자경고 종목을 매수주문하는 경우 - 경고 메세지 창이 출력되도록 기능이 추가 되었습니다. (경고 창 출력 시 주문을 중지/전송 선택 가능합니다.) - 주문 함수를 호출하기 전에 특정 종목이 투자유의종목인지 아래와 같은 방법으로 확인할 수 있습니다. - - >>> KOA_Functions("IsOrderWarningStock", "종목코드(6자리)") - - 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 - - 9. 상장주식수 구하기 (2021/04/08 적용) - 상장주식수를 구하는 GetMasterListedStockCnt() 기존 함수 사용시 특정 종목 데이터가 long 형을 Overflow 하는 현상이 있습니다. - 이에, 상장주식수를 구하는 기능을 신규 추가 합니다. 사용법은 아래와 같습니다. - - >>> KOA_Functions("GetMasterListedStockCntEx", "종목코드(6자리)") - - 10. 종목코드로 Market구분 구하기 (2022/3/3 적용) - 종목코드 입력으로 해당 종목이 어느 시장에 포함되어 있는지 구하는 기능 - 서버와의 통신없이 메모리에 상주하는 값을 사용하므로 횟수제한 등은 없습니다. 사용법은 아래와 같습니다. - - >>> KOA_Functions("GetStockMarketKind", "종목코드6자리") - - 리턴값은 문자형으로 아래와 같습니다. - "0":코스피, "10":코스닥, "3":ELW, "8":ETF, "4"/"14":뮤추얼펀드, "6"/"16":리츠, "9"/"19":하이일드펀드, "30":제3시장, "60":ETN - - Args: - sFunctionName (str): 함수이름 혹은 기능이름 - sParam (str): 함수 매개변수 - - Returns: - str: 결과 데이터 - """ - ... - - def SetInfoData(self, sInfoData: str) -> int: - """ - 다수의 아이디로 자동로그인이 필요할 때 사용한다. - - Args: - sInfoData (str): 아이디 - - Returns: - int: 통신결과 - - Examples: - >>> SetInfoData("UserID") - """ - ... - - def SetRealReg( - self, strScreenNo: str, strCodeList: str, strFidList: str, strOptType: str - ) -> int: - """ - 실시간 등록을 한다. - - 종목코드와 FID 리스트를 이용해서 실시간 시세를 등록하는 함수입니다. - 한번에 등록가능한 종목과 FID갯수는 100종목, 100개 입니다. - 실시간 등록타입을 0으로 설정하면 등록한 종목들은 실시간 해지되고 등록한 종목만 실시간 시세가 등록됩니다. - 실시간 등록타입을 1로 설정하면 먼저 등록한 종목들과 함께 실시간 시세가 등록됩니다 - - strOptType 이 "0" 으로 하면 같은 화면에서 다른 종목 코드로 실시간 등록을 하게 되면 - 마지막에 사용한 종목코드만 실시간 등록이 되고 기존에 있던 종목은 실시간이 자동 해지됨. - "1" 로 하면 같은 화면에서 다른 종목들을 추가하게 되면 기존에 등록한 종목도 함께 실시간 시세를 받을 수 있음. - 꼭 같은 화면이여야 하고 최초 실시간 등록은 "0" 으로 하고 이후부터 "1" 로 등록해야함. - - Args: - strScreenNo (str): 화면번호 (4자리) - strCodeList (str): 종목코드 (복수종목가능, ';' 구분자) - strFidList (str): FID (';' 구분자) - strOptType (str): 등록타입 (0:최초 등록시, 혹은 기존 등록된 종목 해지하고 등록 1:기존 등록된 종목 유지하고 등록) - - Returns: - int: 통신결과 - """ - ... - - def GetConditionLoad(self) -> int: - """ - 서버에 저장된 사용자 조건식을 조회해서 임시로 파일에 저장. - - 서버에 저장된 사용자 조건검색 목록을 요청합니다. - 조건검색 목록을 모두 수신하면 OnReceiveConditionVer() 이벤트가 발생됩니다. - 조건검색 목록 요청을 성공하면 1, 아니면 0을 리턴합니다. - - System 폴더에 아이디_NewSaveIndex.dat 파일로 저장된다. OCX 가 종료되면 삭제시킨다. - 조건검색 사용시 이 함수를 최소 한번은 호출해야 조건검색을 할 수 있다. - 영웅문에서 사용자 조건을 수정 및 추가하였을 경우에도 최신의 사용자 조건을 받고 싶으면 다시 - 조회해야한다. - - Returns: - int: 성공하면 1, 아니면 0을 반환 - """ - ... - - def GetConditionNameList(self) -> str: - """ - 조건검색 조건명 리스트를 받아온다. - - 서버에서 수신한 사용자 조건식을 조건식의 고유번호와 조건식 이름을 한 쌍으로 하는 문자열들로 전달합니다. - 조건식 하나는 조건식의 고유번호와 조건식 이름이 구분자 '^' 로 나뉘어져 있으며 각 조건식은 ';' 로 나뉘어져 있습니다. - 이 함수는 OnReceiveConditionVer() 이벤트에서 사용해야 합니다. - - Returns: - str: 조건명 리스트 문자열 - - Examples: - >>> GetConditionNameList() - "1^내조건식1;2^내조건식2;5^내조건식3;..." - """ - ... - - def SendCondition( - self, strScrNo: str, strConditionName: str, nIndex: int, nSearch: int - ) -> int: - """ - 조건검색 종목조회TR을 송신한다. - - 서버에 조건검색을 요청하는 함수입니다. - 마지막 인자값으로 조건검색만 할것인지 실시간 조건검색도 수신할 것인지를 지정할 수 있습니다. - GetConditionNameList() 함수로 얻은 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. - 리턴값 1이면 성공이며, 0이면 실패입니다. - 요청한 조건식이 없거나 조건 고유번호와 조건명이 서로 안맞거나 조회횟수를 초과하는 경우 실패하게 됩니다. - - 단순 조건식에 맞는 종목을 조회하기 위해서는 조회구분을 0으로 하고, - 실시간 조건검색을 하기 위해서는 조회구분을 1로 한다. - OnReceiveTrCondition() 으로 결과값이 온다. - 연속조회가 필요한 경우에는 응답받는 곳에서 연속조회 여부에 따라 연속조회를 송신하면된다. - - Args: - strScrNo (str): 화면번호 - strConditionName (str): 조건식 이름 - nIndex (int): 조건식 인덱스 - nSearch (int): 조회구분 (0:일반조회, 1:실시간조회 (최초 일반조회 + 이후 실시간조회), 2:연속조회) - - Returns: - int: 성공하면 1, 아니면 0을 반환 - """ - ... - - def SendConditionStop( - self, strScrNo: str, strConditionName: str, nIndex: int - ) -> None: - """ - 조건검색 실시간 중지TR을 송신한다. - - 실시간 조건검색을 중지할 때 사용하는 함수입니다. - 조건식 조회할때 얻는 조건식 이름과 고유번호의 쌍을 맞춰서 사용해야 합니다. - - 해당 조건명의 실시간 조건검색을 중지하거나, - 다른 조건명으로 바꿀 때 이전 조건명으로 실시간 조건검색을 반드시 중지해야한다. - 화면 종료시에도 실시간 조건검색을 한 조건명으로 전부 중지해줘야 한다. - - Args: - strScrNo (str): 화면번호 - strConditionName (str): 조건식 이름 - nIndex (int): 조건식 인덱스 - - Returns: - None - """ - ... - - def GetCommDataEx(self, strTrCode: str, strRecordName: str): - """ - 차트 조회 데이터를 배열로 받아온다. - - 조회 수신데이터 크기가 큰 차트데이터를 한번에 가져올 목적으로 만든 차트조회 전용함수입니다. - - 조회 데이터가 많은 차트 경우 GetCommData()로 항목당 하나씩 받아오는 것 보다 - 한번에 데이터 전부를 받아서 사용자가 처리할 수 있도록 배열로 받는다. - - ※ Qt 기준으로 QVariant 타입의 배열을 반환하지만 PySide2 에서는 완전히 똑같이 지원하진 않습니다. - - Args: - strTrCode (str): TR코드 - strRecordName (str): 레코드명 - - Returns: - QVariant: 조회 데이터 배열 - """ - ... - - def SetRealRemove(self, strScrNo: str, strDelCode: str) -> None: - """ - 종목별 실시간 해제. - - 실시간시세 해지 함수이며 화면번호와 종목코드를 이용해서 상세하게 설정할 수 있습니다. - - ※ A종목에 대한 실시간이 여러 화면번호로 중복 등록되어 있는 경우 특정 화면번호를 이용한 - SetRealRemove() 함수호출시 A종목의 실시간시세는 해지되지 않습니다. - - SetRealReg() 함수로 실시간 등록한 종목만 실시간 해제 할 수 있다. - - Args: - strScrNo (str): 화면번호 (4자리) 또는 "ALL" - strDelCode (str): 종목코드 또는 "ALL" - - Returns: - None - """ - ... - - def GetMarketType(self, sTrCode: str) -> int: - """ - 주어진 종목코드의 시장구분값을 가져온다. - - 시장 구분: - - 0: 장내 - - 3: ELW - - 4: 뮤추얼펀드 - - 5: 신주인수권 - - 6: 리츠 - - 8: ETF - - 9: 하이일드펀드 - - 10: 코스닥 - - 30: K-OTC - - 50: 코넥스 (KONEX) - - Args: - sTrCode (str): 종목코드 - - Returns: - int: 시장 구분값 - """ - ... diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.py deleted file mode 100644 index 462c67ac..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -from typing import Dict, List - -import pythoncom - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import ( - KiwoomOpenApiPlusDispatchFunctions, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature import ( - KiwoomOpenApiPlusSignature, -) -from koapy.utils.builtin import dir_public - - -class KiwoomOpenApiPlusDispatchSignature(KiwoomOpenApiPlusSignature): - - DISPATCH_SIGNATURES_BY_NAME: Dict[str, KiwoomOpenApiPlusDispatchSignature] = {} - - @classmethod - def from_name(cls, name: str) -> KiwoomOpenApiPlusDispatchSignature: - signature = cls.DISPATCH_SIGNATURES_BY_NAME[name] - return signature - - @classmethod - def names(cls) -> List[str]: - names = cls.DISPATCH_SIGNATURES_BY_NAME.keys() - names = list(names) - if not names: - _names = dir_public(KiwoomOpenApiPlusDispatchFunctions) - return names - - @classmethod - def _make_dispatch_signatures_by_name( - cls, - ) -> Dict[str, KiwoomOpenApiPlusDispatchSignature]: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( - DISPATCH_OLE_ITEM, - ) - - dispatch = DISPATCH_OLE_ITEM - dispatch_signatures_by_name: Dict[str, KiwoomOpenApiPlusDispatchSignature] = {} - if dispatch: - dispatch_funcs = [ - (name, entry) - for name, entry in dispatch.mapFuncs.items() - if not any( - [ - entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED - and entry.desc[0] != pythoncom.DISPID_NEWENUM, - entry.desc[3] != pythoncom.FUNC_DISPATCH, - entry.desc[0] == pythoncom.DISPID_NEWENUM, - ] - ) - ] - for func_name, entry in dispatch_funcs: - signature = cls._from_entry(func_name, entry) - dispatch_signatures_by_name[func_name] = signature - return dispatch_signatures_by_name - - @classmethod - def _initialize(cls): - cls.DISPATCH_SIGNATURES_BY_NAME = cls._make_dispatch_signatures_by_name() - - -KiwoomOpenApiPlusDispatchSignature._initialize() # pylint: disable=protected-access diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.py deleted file mode 100644 index 8fe902ba..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable.py +++ /dev/null @@ -1,83 +0,0 @@ -from __future__ import annotations - -from inspect import Signature -from typing import Any, Callable, List, Sequence - -try: - from typing import ParamSpec, TypeVar -except ImportError: - from typing_extensions import ParamSpec - from typing import TypeVar - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import ( - KiwoomOpenApiPlusDispatchSignature, -) -from koapy.compat.pyside2.QtAxContainer import QAxWidget - -P = ParamSpec("P") -R = TypeVar("R") - - -class KiwoomOpenApiPlusDynamicCallable(Callable[P, R]): - def __init__( - self, - control: QAxWidget, - name: str, - ): - self._control = control - self._name = name - - self._signature = KiwoomOpenApiPlusDispatchSignature.from_name(self._name) - self._function = self._signature.to_pyside2_function_prototype() - self._has_return_value = ( - self._signature.return_annotation is not Signature.empty - ) - - self.__name__ = self._name - self.__signature__ = self._signature - - def bind_dynamic_call_args(self, *args, **kwargs) -> List[Any]: - try: - ba = self._signature.bind(*args, **kwargs) - except TypeError as e: - raise TypeError( - "Exception while binding arguments for function: %s" % self._name - ) from e - ba.apply_defaults() - args = list(ba.args) - return args - - def is_valid_return_type(self, result: Any) -> bool: - is_valid = True - if self._has_return_value: - if not isinstance(result, self._signature.return_annotation): - is_valid = False - return is_valid - - def check_return_value(self, result: Any): - if not self.is_valid_return_type(result): - raise TypeError( - "Return type of %s was expected for function call %s(...), but %s was found" - % ( - self._signature.return_annotation, - self._name, - type(result), - ) - ) - return result - - def dynamic_call(self, args: Sequence[Any]) -> R: - return self._control.dynamicCall(self._function, args) - - def dynamic_call_and_check(self, args: Sequence[Any]) -> R: - result = self.dynamic_call(args) - self.check_return_value(result) - return result - - def call(self, *args: P.args, **kwargs: P.kwargs) -> R: - args = self.bind_dynamic_call_args(*args, **kwargs) - result = self.dynamic_call_and_check(args) - return result - - def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: - return self.call(*args, **kwargs) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.py deleted file mode 100644 index 649729f1..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint.py +++ /dev/null @@ -1,100 +0,0 @@ -import threading - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin import ( - KiwoomOpenApiPlusEntrypointMixin, -) -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import ( - KiwoomOpenApiPlusServiceClient, -) -from koapy.config import config, get_32bit_executable -from koapy.utils.logging import get_verbosity -from koapy.utils.logging.Logging import Logging -from koapy.utils.networking import get_free_localhost_port -from koapy.utils.subprocess import Popen - - -class KiwoomOpenApiPlusEntrypoint(KiwoomOpenApiPlusEntrypointMixin, Logging): - def __init__( - self, - port=None, - client_check_timeout=None, - ): - if port is None: - port = ( - config.get("koapy.backend.kiwoom_open_api_plus.grpc.port", 0) - or get_free_localhost_port() - ) - - self._port = port - self._client_check_timeout = client_check_timeout - - self._server_executable = get_32bit_executable() - self._server_proc_args = [self._server_executable, "-m", "koapy.cli", "serve"] - if self._port is not None: - self._server_proc_args.extend(["-p", str(self._port)]) - - self._verbosity = get_verbosity() - self._server_proc_args.extend(["-" + "v" * self._verbosity]) - - self._server_proc = None - self._server_proc_start_timeout = 30 - self._server_proc_terminate_timeout = 30 - - self._client = KiwoomOpenApiPlusServiceClient(port=self._port) - - self.logger.debug("Testing if client is ready...") - if not self._client.is_ready(self._client_check_timeout): - self.logger.debug("Client is not ready") - self.logger.debug("Creating a new server...") - if self._server_executable is None: - raise FileNotFoundError("Cannot find 32bit python executable") - self._server_proc = Popen(self._server_proc_args) - assert self._client.is_ready( - self._server_proc_start_timeout - ), "Failed to create server" - self._stub = self._client.get_stub() - else: - self.logger.debug("Client is ready, using existing server") - self._stub = self._client.get_stub() - - self._context_lock = threading.RLock() - self._enter_count = 0 - - def __del__(self): - self.close() - - def __enter__(self): - with self._context_lock: - self._enter_count += 1 - return self - - def __exit__(self, exc_type, exc_value, traceback): - with self._context_lock: - if self._enter_count > 0: - self._enter_count -= 1 - if self._enter_count == 0: - self.close() - - def get_stub(self): - return self._stub - - def close_client(self): - self._client.close() - - def close_server_proc(self): - if self._server_proc is not None: - self._server_proc.terminate() # maybe soft termination available via grpc? rather than hard termination - self._server_proc.wait(self._server_proc_terminate_timeout) - self._server_proc = None - - def close(self): - self.close_client() - self.close_server_proc() - - def __getattr__(self, name): - try: - stub = self.__getattribute__("_stub") - except AttributeError: - return self.__getattribute__(name) - else: - return getattr(stub, name) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.py deleted file mode 100644 index 65772cba..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin.py +++ /dev/null @@ -1,2 +0,0 @@ -class KiwoomOpenApiPlusEntrypointMixin: - pass diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.py deleted file mode 100644 index 1a3c1aa6..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError.py +++ /dev/null @@ -1,347 +0,0 @@ -from concurrent.futures import Future -from functools import wraps -from typing import Callable, Optional, TypeVar, Union - -CallableReturnsInt = Callable[..., int] - -IntOrBool = TypeVar( - "IntOrBool", - int, - bool, -) - -CallableReturnsIntOrBool = TypeVar( - "CallableReturnsIntOrBool", - Callable[..., int], - Callable[..., bool], -) - -IntCompatible = TypeVar( - "IntCompatible", - int, - Callable[..., int], - Future, -) - -BoolCompatible = TypeVar( - "BoolCompatible", - int, - bool, - Callable[..., int], - Callable[..., bool], - Future, -) - - -class KiwoomOpenApiPlusError(Exception): - def __init__(self, message: Optional[str] = None): - if message is not None: - super().__init__(message) - else: - super().__init__() - - self._message = message - - @property - def message(self): - return self._message - - @classmethod - def try_or_raise( - cls, - arg: IntCompatible, - message: Optional[str] = None, - except_callback: Optional[Callable] = None, - ) -> IntCompatible: - return KiwoomOpenApiPlusNegativeReturnCodeError.try_or_raise( - arg, message, except_callback - ) - - @classmethod - def try_or_raise_boolean( - cls, - arg: BoolCompatible, - message: str, - except_callback: Optional[Callable] = None, - ) -> BoolCompatible: - return KiwoomOpenApiPlusBooleanReturnCodeError.try_or_raise( - arg, message, except_callback - ) - - @classmethod - def get_error_message_by_code(cls, code: int, default: Optional[str] = None): - return KiwoomOpenApiPlusNegativeReturnCodeError.get_error_message_by_code( - code, default - ) - - -class KiwoomOpenApiPlusNegativeReturnCodeError(KiwoomOpenApiPlusError): - - OP_ERR_NONE = 0 - OP_ERR_FAIL = -10 - OP_ERR_COND_NOTFOUND = -11 - OP_ERR_COND_MISMATCH = -12 - OP_ERR_COND_OVERFLOW = -13 - OP_ERR_TR_FAIL = -22 - OP_ERR_LOGIN = -100 - OP_ERR_CONNECT = -101 - OP_ERR_VERSION = -102 - OP_ERR_FIREWALL = -103 - OP_ERR_MEMORY = -104 - OP_ERR_INPUT = -105 - OP_ERR_SOCKET_CLOSED = -106 - OP_ERR_SISE_OVERFLOW = -200 - OP_ERR_RQ_STRUCT_FAIL = -201 - OP_ERR_RQ_STRING_FAIL = -202 - OP_ERR_NO_DATA = -203 - OP_ERR_OVER_MAX_DATA = -204 - OP_ERR_DATA_RCV_FAIL = -205 - OP_ERR_OVER_MAX_FID = -206 - OP_ERR_REAL_CANCEL = -207 - OP_ERR_ORD_WRONG_INPUT = -300 - OP_ERR_ORD_WRONG_ACCTNO = -301 - OP_ERR_OTHER_ACC_USE = -302 - OP_ERR_MIS_2BILL_EXC = -303 - OP_ERR_MIS_5BILL_EXC = -304 - OP_ERR_MIS_1PER_EXC = -305 - OP_ERR_MIS_3PER_EXC = -306 - OP_ERR_SEND_FAIL = -307 - OP_ERR_ORD_OVERFLOW = -308 - OP_ERR_ORD_OVERFLOW2 = -311 - OP_ERR_MIS_300CNT_EXC = -309 - OP_ERR_MIS_500CNT_EXC = -310 - OP_ERR_ORD_WRONG_ACCTINFO = -340 - OP_ERR_ORD_SYMCODE_EMPTY = -500 - - MSG_ERR_NONE = "정상처리" - MSG_ERR_FAIL = "실패" - MSG_ERR_COND_NOTFOUND = "조건번호 없음" - MSG_ERR_COND_MISMATCH = "조건번호와 조건식 틀림" - MSG_ERR_COND_OVERFLOW = "조건검색 조회요청 초과" - MSG_ERR_TR_FAIL = "전문 처리 실패" - MSG_ERR_LOGIN = "사용자정보 교환 실패" - MSG_ERR_CONNECT = "서버접속 실패" - MSG_ERR_VERSION = "버전처리 실패" - MSG_ERR_FIREWALL = "개인방화벽 실패" - MSG_ERR_MEMORY = "메모리보호 실패" - MSG_ERR_INPUT = "함수입력값 오류" - MSG_ERR_SOCKET_CLOSED = "통신 연결종료" - MSG_ERR_SISE_OVERFLOW = "시세조회 과부하" - MSG_ERR_RQ_STRUCT_FAIL = "전문작성 초기화 실패" - MSG_ERR_RQ_STRING_FAIL = "전문작성 입력값 오류" - MSG_ERR_NO_DATA = "데이터 없음" - MSG_ERR_OVER_MAX_DATA = "조회 가능한 종목수 초과" - MSG_ERR_DATA_RCV_FAIL = "데이터수신 실패" - MSG_ERR_OVER_MAX_FID = "조회 가능한 FID수 초과" - MSG_ERR_REAL_CANCEL = "실시간 해제 오류" - MSG_ERR_ORD_WRONG_INPUT = "입력값 오류" - MSG_ERR_ORD_WRONG_ACCTNO = "계좌 비밀번호 없음" - MSG_ERR_OTHER_ACC_USE = "타인계좌사용 오류" - MSG_ERR_MIS_2BILL_EXC = "주문가격이 20억원을 초과" - MSG_ERR_MIS_5BILL_EXC = "주문가격이 50억원을 초과" - MSG_ERR_MIS_1PER_EXC = "주문수량이 총발행주수의 1%초과오류" - MSG_ERR_MIS_3PER_EXC = "주문수량이 총발행주수의 3%초과오류" - MSG_ERR_SEND_FAIL = "주문전송 실패" - MSG_ERR_ORD_OVERFLOW = "주문전송 과부하" - MSG_ERR_ORD_OVERFLOW2 = "주문전송 과부하" - MSG_ERR_MIS_300CNT_EXC = "주문수량 300계약 초과" - MSG_ERR_MIS_500CNT_EXC = "주문수량 500계약 초과" - MSG_ERR_ORD_WRONG_ACCTINFO = "계좌정보없음" - MSG_ERR_ORD_SYMCODE_EMPTY = "종목코드없음" - - ERROR_MESSAGE_BY_CODE = { - OP_ERR_NONE: MSG_ERR_NONE, - OP_ERR_FAIL: MSG_ERR_FAIL, - OP_ERR_COND_NOTFOUND: MSG_ERR_COND_NOTFOUND, - OP_ERR_COND_MISMATCH: MSG_ERR_COND_MISMATCH, - OP_ERR_COND_OVERFLOW: MSG_ERR_COND_OVERFLOW, - OP_ERR_TR_FAIL: MSG_ERR_TR_FAIL, - OP_ERR_LOGIN: MSG_ERR_LOGIN, - OP_ERR_CONNECT: MSG_ERR_CONNECT, - OP_ERR_VERSION: MSG_ERR_VERSION, - OP_ERR_FIREWALL: MSG_ERR_FIREWALL, - OP_ERR_MEMORY: MSG_ERR_MEMORY, - OP_ERR_INPUT: MSG_ERR_INPUT, - OP_ERR_SOCKET_CLOSED: MSG_ERR_SOCKET_CLOSED, - OP_ERR_SISE_OVERFLOW: MSG_ERR_SISE_OVERFLOW, - OP_ERR_RQ_STRUCT_FAIL: MSG_ERR_RQ_STRUCT_FAIL, - OP_ERR_RQ_STRING_FAIL: MSG_ERR_RQ_STRING_FAIL, - OP_ERR_NO_DATA: MSG_ERR_NO_DATA, - OP_ERR_OVER_MAX_DATA: MSG_ERR_OVER_MAX_DATA, - OP_ERR_DATA_RCV_FAIL: MSG_ERR_DATA_RCV_FAIL, - OP_ERR_OVER_MAX_FID: MSG_ERR_OVER_MAX_FID, - OP_ERR_REAL_CANCEL: MSG_ERR_REAL_CANCEL, - OP_ERR_ORD_WRONG_INPUT: MSG_ERR_ORD_WRONG_INPUT, - OP_ERR_ORD_WRONG_ACCTNO: MSG_ERR_ORD_WRONG_ACCTNO, - OP_ERR_OTHER_ACC_USE: MSG_ERR_OTHER_ACC_USE, - OP_ERR_MIS_2BILL_EXC: MSG_ERR_MIS_2BILL_EXC, - OP_ERR_MIS_5BILL_EXC: MSG_ERR_MIS_5BILL_EXC, - OP_ERR_MIS_1PER_EXC: MSG_ERR_MIS_1PER_EXC, - OP_ERR_MIS_3PER_EXC: MSG_ERR_MIS_3PER_EXC, - OP_ERR_SEND_FAIL: MSG_ERR_SEND_FAIL, - OP_ERR_ORD_OVERFLOW: MSG_ERR_ORD_OVERFLOW, - OP_ERR_ORD_OVERFLOW2: MSG_ERR_ORD_OVERFLOW2, - OP_ERR_MIS_300CNT_EXC: MSG_ERR_MIS_300CNT_EXC, - OP_ERR_MIS_500CNT_EXC: MSG_ERR_MIS_500CNT_EXC, - OP_ERR_ORD_WRONG_ACCTINFO: MSG_ERR_ORD_WRONG_ACCTINFO, - OP_ERR_ORD_SYMCODE_EMPTY: MSG_ERR_ORD_SYMCODE_EMPTY, - } - - @classmethod - def get_error_message_by_code(cls, code: int, default: Optional[str] = None): - return cls.ERROR_MESSAGE_BY_CODE.get(code, default) - - @classmethod - def check_code_or_raise(cls, code: int): - if code < 0: - raise cls(code) - return code - - @classmethod - def wrap_to_check_code_or_raise( - cls, func: CallableReturnsInt - ) -> CallableReturnsInt: - @wraps(func) - def wrapper(*args, **kwargs): - return cls.check_code_or_raise(func(*args, **kwargs)) - - return wrapper - - @classmethod - def try_or_raise( - cls, - arg: IntCompatible, - message: Optional[str] = None, - except_callback: Optional[Callable] = None, - ) -> IntCompatible: - if isinstance(arg, Future): - - def callback(future): - exc = future.exception() - if exc: - if except_callback: - except_callback(exc) - else: - raise exc - result = future.result() - try: - cls.try_or_raise(result, message) - except cls as e: - if except_callback: - except_callback(e) - else: - raise - - arg.add_done_callback(callback) - return arg - elif isinstance(arg, int): - return cls.check_code_or_raise(arg) - elif callable(arg): - return cls.wrap_to_check_code_or_raise(arg) - else: - raise TypeError( - "Expected 'int', 'callable' or 'Future' but %s found" % type(arg) - ) - - def __init__(self, code: int, message: Optional[str] = None): - if message is None: - message = self.get_error_message_by_code(code) - - super().__init__(message) - - self._code = code - self._message = message - - def __str__(self): - return self._message - - def __repr__(self): - return "{}({!r}, {!r})".format( - self.__class__.__name__, self._code, self._message - ) - - @property - def code(self): - return self._code - - -class KiwoomOpenApiPlusBooleanReturnCodeError(KiwoomOpenApiPlusError): - - OP_ERR_SUCCESS = 1 - OP_ERR_FAILURE = 0 - - @classmethod - def check_code_or_raise( - cls, code: IntOrBool, message: Optional[str] = None - ) -> IntOrBool: - if not code: - raise cls(code, message) - return code - - @classmethod - def wrap_to_check_code_or_raise( - cls, func: CallableReturnsIntOrBool, message: Optional[str] = None - ) -> CallableReturnsIntOrBool: - @wraps(func) - def wrapper(*args, **kwargs): - return cls.check_code_or_raise(func(*args, **kwargs), message) - - return wrapper - - @classmethod - def try_or_raise( - cls, - arg: BoolCompatible, - message: Optional[str] = None, - except_callback: Optional[Callable] = None, - ) -> BoolCompatible: - if isinstance(arg, Future): - - def callback(future): - exc = future.exception() - if exc: - if except_callback: - except_callback(exc) - else: - raise exc - result = future.result() - try: - cls.try_or_raise(result, message) - except cls as e: - if except_callback: - except_callback(e) - else: - raise - - arg.add_done_callback(callback) - return arg - elif isinstance(arg, (int, bool)): - return cls.check_code_or_raise(arg, message) - elif callable(arg): - return cls.wrap_to_check_code_or_raise(arg, message) - else: - raise TypeError( - "Expected 'int', 'bool', 'callable' or 'Future' but %s found" - % type(arg) - ) - - def __init__(self, code: Union[int, bool], message: Optional[str] = None): - super().__init__(message) - - self._code = code - self._message = message - - def __str__(self): - if self._message: - return self._message - else: - return self.__repr__() - - def __repr__(self): - return "{}({!r}, {!r})".format( - self.__class__.__name__, self._code, self._message - ) - - @property - def code(self): - return self._code diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.py deleted file mode 100644 index 8cd31107..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions.py +++ /dev/null @@ -1,191 +0,0 @@ -# pylint: disable=unused-argument,unnecessary-ellipsis - - -class KiwoomOpenApiPlusEventFunctions: - def OnReceiveTrData( - self, - sScrNo: str, - sRQName: str, - sTrCode: str, - sRecordName: str, - sPrevNext: str, - nDataLength: int, - sErrorCode: str, - sMessage: str, - sSplmMsg: str, - ) -> None: - """ - 서버통신 후 데이터를 받은 시점을 알려준다. - - 요청했던 조회데이터를 수신했을때 발생됩니다. - 수신된 데이터는 이 이벤트내부에서 GetCommData() 함수를 이용해서 얻어올 수 있습니다. - - 파라미터 매핑: - - sRQName = CommRqData() 의 sRQName과 매핑되는 이름이다. - - sTrCode = CommRqData() 의 sTrCode과 매핑되는 이름이다. - - Args: - sScrNo (str): 화면번호 - sRQName (str): 사용자 구분명 - sTrCode (str): TR 코드 - sRecordName (str): 레코드 명 - sPrevNext (str): 연속조회 유무 (0:추가조회 데이터 없음, 2:추가조회 데이터 있음) - nDataLength (str): 사용안함 - sErrorCode (str): 사용안함 - sMessage (str): 사용안함 - sSplmMsg (str): 사용안함 - - Returns: - None - """ - ... - - def OnReceiveRealData(self, sRealKey: str, sRealType: str, sRealData: str) -> None: - """ - 실시간데이터를 받은 시점을 알려준다. - - 실시간시세 데이터가 수신될때마다 종목단위로 발생됩니다. - SetRealReg() 함수로 등록한 실시간 데이터도 이 이벤트로 전달됩니다. - GetCommRealData() 함수를 이용해서 수신된 데이터를 얻을수 있습니다. - - Args: - sRealKey (str): 종목코드 - sRealType (str): 실시간 타입 - sRealData (str): 실시간 데이터전문 (사용불가) - - Returns: - None - """ - ... - - def OnReceiveMsg(self, sScrNo: str, sRQName: str, sTrCode: str, sMsg: str) -> None: - """ - 서버통신 후 메시지를 받은 시점을 알려준다. - - 주문전송 또는 데이터 조회요청 후 서버 메시지가 수신됩니다. - ※ 메시지에 포함된 6자리 코드번호는 변경될 수 있으니, 여기에 수신된 코드번호를 특정 용도로 사용하지 마시기 바랍니다. - - 파라미터 매핑: - - sScrNo = CommRqData() 의 sScrNo와 매핑된다. - - sRQName = CommRqData() 의 sRQName 와 매핑된다. - - sTrCode = CommRqData() 의 sTrCode 와 매핑된다. - - 메시지 예시: - - "조회가 완료되었습니다." - - "증거금 부족으로 주문이 거부되었습니다." - - "정정할 원주문 내역이 없습니다." - - "비밀번호 입력을 확인해주시기 바랍니다." - - Args: - sScrNo: str, sRQName: str, sTrCode: str, sMsg: str - - Returns: - None - """ - ... - - def OnReceiveChejanData(self, sGubun: str, nItemCnt: int, sFIdList: str) -> None: - """ - 체결데이터를 받은 시점을 알려준다. - - 주문전송 후 주문접수, 체결통보, 잔고통보를 수신할 때 마다 발생됩니다. - GetChejanData() 함수를 이용해서 FID 항목별 값을 얻을수 있습니다. - - Args: - sGubun (str): 체결구분 (0:주문체결통보, 1:국내주식 잔고통보, 4:파생상품 잔고통보) - nItemCnt (int): 아이템 개수 - sFIdList (str): 데이터 리스트 (';' 구분자) - - Returns: - None - """ - ... - - def OnEventConnect(self, nErrCode: int) -> None: - """ - 서버 접속 관련 이벤트. - - 로그인 처리 이벤트입니다. 성공이면 인자값 nErrCode가 0이며 에러는 다음과 같은 값이 전달됩니다. - - 에러코드 구분: - - OP_ERR_LOGIN(-100): 사용자 정보교환 실패 - - OP_ERR_CONNECT(-101): 서버접속 실패 - - OP_ERR_VERSION(-102): 버전처리 실패 - - Args: - nErrCode (int): 에러코드 (0:로그인 성공, 음수:실패) - - Returns: - None - """ - ... - - def OnReceiveInvestRealData(self, sRealKey: str) -> None: - """ - 더 이상 지원하지 않는 함수. - """ - ... - - def OnReceiveRealCondition( - self, sTrCode: str, strType: str, strConditionName: str, strConditionIndex: str - ) -> None: - """ - 조건검색 실시간 편입,이탈 종목을 받을 시점을 알려준다. - - 실시간 조건검색 요청으로 신규종목이 편입되거나 기존 종목이 이탈될때 마다 발생됩니다. - ※ 편입되었다가 순간적으로 다시 이탈되는 종목에대한 신호는 조건검색 서버마다 차이가 발생할 수 있습니다. - - strConditionName 에 해당하는 종목이 실시간으로 들어옴. - strType 으로 편입된 종목인지 이탈된 종목인지 구분한다. - - Args: - sTrCode (str): 종목코드 - strType (str): 편입/이탈 구분 (I:편입, D:이탈) - strConditionName (str): 조건식 이름 - strConditionIndex (str): 조건식 인덱스 - - Returns: - None - """ - ... - - def OnReceiveTrCondition( - self, - sScrNo: str, - strCodeList: str, - strConditionName: str, - nIndex: int, - nNext: int, - ) -> None: - """ - 조건검색 조회응답으로 종목리스트를 받는 시점. - - 조건검색 요청에대한 서버 응답 수신시 발생하는 이벤트입니다. - 종목코드 리스트는 각 종목코드가 ';' 로 구분되서 전달됩니다. - - Args: - sScrNo (str): 화면번호 - strCodeList (str): 종목리스트 (';' 구분자) - strConditionName (str): 조건식 이름 - nIndex (int): 조건식 인덱스 - nNext (int): 연속조회 여부 (2:연속조회, 0:연속조회 없음) - - Returns: - None - """ - ... - - def OnReceiveConditionVer(self, lRet: int, sMsg: str) -> None: - """ - 로컬에 사용자 조건식 저장 성공 여부를 확인하는 시점. - - 저장된 사용자 조건식 불러오기 요청에 대한 응답 수신시 발생되는 이벤트입니다. - - Args: - lRet (int): 사용자 조건식 저장 성공여부 (1:성공, 나머지:실패) - sMsg (str): 호출결과 메시지 - - Returns: - None - """ - ... diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.py deleted file mode 100644 index 268c4d83..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler.py +++ /dev/null @@ -1,106 +0,0 @@ -from contextlib import ExitStack -from threading import RLock - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions import ( - KiwoomOpenApiPlusEventHandlerFunctions, -) -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import ( - QueueBasedIterableObserver, -) -from koapy.utils.notimplemented import isimplemented - - -class KiwoomOpenApiPlusEventHandler(KiwoomOpenApiPlusEventHandlerFunctions): - # pylint: disable=abstract-method - - def __init__(self, control): - self._control = control - self._observer = QueueBasedIterableObserver() - self._enter_count = 0 - self._should_exit = False - self._stack = ExitStack() - self._lock = RLock() - - @property - def control(self): - return self._control - - @property - def observer(self): - return self._observer - - @classmethod - def names(cls): - names = [ - name - for name in dir(KiwoomOpenApiPlusEventHandlerFunctions) - if name.startswith("On") - ] - return names - - def slots(self): - names = self.names() - slots = [getattr(self, name) for name in names] - names_and_slots_implemented = [ - (name, slot) for name, slot in zip(names, slots) if isimplemented(slot) - ] - return names_and_slots_implemented - - def connect(self): - for name, slot in self.slots(): - getattr(self.control, name).connect(slot) - - def disconnect(self): - for name, slot in self.slots(): - getattr(self.control, name).disconnect(slot) - - def on_enter(self): - pass - - def on_exit(self, exc_type=None, exc_value=None, traceback=None): - pass - - def add_callback(self, callback, *args, **kwargs): - self._stack.callback(callback, *args, **kwargs) - - def enter(self): - with self._lock: - self.connect() - self.on_enter() - self._should_exit = True - - def exit(self, exc_type=None, exc_value=None, traceback=None): - with self._lock: - if self._should_exit: - self.disconnect() - self.on_exit(exc_type, exc_value, traceback) - self._stack.__exit__(exc_type, exc_value, traceback) - self._should_exit = False - - def stop(self): - return self.observer.stop() - - def close(self): - self.exit() - self.stop() - - def __enter__(self): - with self._lock: - if self._enter_count == 0: - self.enter() - self._enter_count += 1 - return self - - def __exit__(self, exc_type, exc_value, traceback): - if exc_type is not None: - return self.exit(exc_type, exc_value, traceback) - with self._lock: - if self._enter_count > 0: - self._enter_count -= 1 - if self._enter_count == 0: - return self.exit(exc_type, exc_value, traceback) - return - - def __iter__(self): - with self: - return iter(self.observer) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.py deleted file mode 100644 index 0015781b..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions.py +++ /dev/null @@ -1,50 +0,0 @@ -from koapy.utils.notimplemented import notimplemented - - -class KiwoomOpenApiPlusEventHandlerFunctions: - @notimplemented - def OnEventConnect(self, errcode): - raise NotImplementedError - - @notimplemented - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - raise NotImplementedError - - @notimplemented - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - raise NotImplementedError - - @notimplemented - def OnReceiveRealData(self, code, realtype, realdata): - raise NotImplementedError - - @notimplemented - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - raise NotImplementedError - - @notimplemented - def OnReceiveConditionVer(self, ret, msg): - raise NotImplementedError - - @notimplemented - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - raise NotImplementedError - - @notimplemented - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - raise NotImplementedError diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.py deleted file mode 100644 index ecbb6fbd..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from typing import Dict, List - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions import ( - KiwoomOpenApiPlusEventFunctions, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature import ( - KiwoomOpenApiPlusSignature, -) -from koapy.utils.builtin import dir_public - - -class KiwoomOpenApiPlusEventHandlerSignature(KiwoomOpenApiPlusSignature): - - EVENT_HANDLER_SIGNATURES_BY_NAME: Dict[ - str, KiwoomOpenApiPlusEventHandlerSignature - ] = {} - - @classmethod - def from_name(cls, name: str) -> KiwoomOpenApiPlusEventHandlerSignature: - signature = cls.EVENT_HANDLER_SIGNATURES_BY_NAME[name] - return signature - - @classmethod - def names(cls) -> List[str]: - names = cls.EVENT_HANDLER_SIGNATURES_BY_NAME.keys() - names = list(names) - if not names: - _names = dir_public(KiwoomOpenApiPlusEventFunctions) - return names - - @classmethod - def _make_event_handler_signatures_by_name( - cls, - ) -> Dict[str, KiwoomOpenApiPlusEventHandlerSignature]: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( - EVENT_OLE_ITEM, - ) - - event = EVENT_OLE_ITEM - event_handler_signatures_by_name: Dict[ - str, KiwoomOpenApiPlusEventHandlerSignature - ] = {} - if event: - event_funcs = event.mapFuncs.items() - event_handler_signatures_by_name = {} - for func_name, entry in event_funcs: - signature = cls._from_entry(func_name, entry) - event_handler_signatures_by_name[func_name] = signature - return event_handler_signatures_by_name - - @classmethod - def _initialize(cls): - cls.EVENT_HANDLER_SIGNATURES_BY_NAME = ( - cls._make_event_handler_signatures_by_name() - ) - - -KiwoomOpenApiPlusEventHandlerSignature._initialize() # pylint: disable=protected-access diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.py deleted file mode 100644 index 69986d77..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler.py +++ /dev/null @@ -1,115 +0,0 @@ -import datetime - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import ( - KiwoomOpenApiPlusEventHandler, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusLoggingEventHandler(KiwoomOpenApiPlusEventHandler, Logging): - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - self.logger.debug( - "OnReceiveTrData(%r, %r, %r, %r, %r)", - scrnno, - rqname, - trcode, - recordname, - prevnext, - ) - - def OnReceiveRealData(self, code, realtype, realdata): - self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata) - if code == "09" and realtype == "장시작시간": - signal_type = self.control.GetCommRealData(code, 215) - current_time = self.control.GetCommRealData(code, 20) - estimated_remaining_time = self.control.GetCommRealData(code, 214) - signal_type_msg = { - # 아래는 문서에서 확인 가능 - "0": "장시작전(동시호가시작,이후1분단위)", - "2": "장종료전(동시호가시작,이후1분단위)", - "3": "장시작(동시호가종료)", - "4": "장종료(동시호가종료)", - "8": "장종료(시간내용없음)", - "9": "장마감(시간내용없음)", - # 이후는 추정 - "s": "선물옵션장종료전(동시호가시작)", # 17번반복 - "a": "장후시간외종가시작", - "e": "선물옵션장종료(동시호가종료)", # 17번반복 - "b": "장후시간외종가종료", - "c": "시간외단일가시작", - "d": "시간외단일가종료", - }.get(signal_type, "알수없음") - if signal_type not in ["8", "9"]: - current_time = datetime.datetime.strptime(current_time, "%H%M%S") - else: - current_time = datetime.datetime.now() - ert = datetime.datetime.strptime(estimated_remaining_time, "%H%M%S") - estimated_remaining_time = datetime.timedelta( - hours=ert.hour, minutes=ert.minute, seconds=ert.second - ) - self.logger.debug( - "%s, %s remaining", signal_type_msg, estimated_remaining_time - ) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - """ - [OnReceiveMsg()이벤트] - - OnReceiveMsg( - BSTR sScrNo, // 화면번호 - BSTR sRQName, // 사용자 구분명 - BSTR sTrCode, // TR이름 - BSTR sMsg // 서버에서 전달하는 메시지 - ) - - 서버통신 후 수신한 메시지를 알려줍니다. - 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 - 이 코드번호로 분류하시면 안됩니다. - """ - self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg) - - if msg == "전문 처리 실패(-22)": - self.logger.warning("Server might have ended connection abruptly") - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist) - - def OnEventConnect(self, errcode): - self.logger.debug("OnEventConnect(%r)", errcode) - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - self.logger.debug( - "OnReceiveRealCondition(%r, %r, %r, %r)", - code, - condition_type, - condition_name, - condition_index, - ) - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - self.logger.debug( - "OnReceiveTrCondition(%r, %r, %r, %r, %r)", - scrnno, - codelist, - condition_name, - condition_index, - prevnext, - ) - - def OnReceiveConditionVer(self, ret, msg): - self.logger.debug("OnReceiveConditionVer(%r, %r)", ret, msg) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.py deleted file mode 100644 index 772041ec..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget.py +++ /dev/null @@ -1,174 +0,0 @@ -from typing import Optional, overload - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import ( - KiwoomOpenApiPlusDispatchSignature, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable import ( - KiwoomOpenApiPlusDynamicCallable, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import ( - KiwoomOpenApiPlusEventHandlerSignature, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler import ( - KiwoomOpenApiPlusLoggingEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetServerSideMixin, - KiwoomOpenApiPlusQAxWidgetUniversalMixin, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector import ( - KiwoomOpenApiPlusSignalConnector, -) -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSlotLikeExecutor import ( - QSlotLikeExecutor, -) -from koapy.compat.pyside2.QtAxContainer import QAxWidget -from koapy.compat.pyside2.QtCore import QEvent, Qt -from koapy.compat.pyside2.QtWidgets import QWidget -from koapy.utils.logging.pyside2.QWidgetLogging import QWidgetLogging -from koapy.utils.platform import is_32bit - - -class KiwoomOpenApiPlusQAxWidget( - QWidgetLogging, - KiwoomOpenApiPlusQAxWidgetUniversalMixin, - KiwoomOpenApiPlusQAxWidgetServerSideMixin, -): - - CLSID = "{A1574A0D-6BFA-4BD7-9020-DED88711818D}" - PROGID = "KHOPENAPI.KHOpenApiCtrl.1" - - METHOD_NAMES = KiwoomOpenApiPlusDispatchSignature.names() - EVENT_NAMES = KiwoomOpenApiPlusEventHandlerSignature.names() - - @overload - def __init__( - self, - c: Optional[str] = None, - parent: Optional[QWidget] = None, - f: Qt.WindowFlags = Qt.WindowFlags(), - ): - ... - - @overload - def __init__( - self, - parent: Optional[QWidget] = None, - f: Qt.WindowFlags = Qt.WindowFlags(), - ): - ... - - def __init__(self, *args, **kwargs): - # Check 32bit requirement - assert is_32bit(), "Control object should be created in 32bit environment" - - # Process arguments - control: Optional[str] = None - parent: Optional[QWidget] = None # pylint: disable=unused-variable - window_flags: Optional[Qt.WindowFlags] = None # pylint: disable=unused-variable - - # Copy args before modification - args = list(args) - kwargs = dict(kwargs) - - # Pop control argument for QWidget init - if len(args) > 0 and isinstance(args[0], str): - control = args.pop(0) - elif "c" in kwargs: - control = kwargs.pop("c") - - # Preserve others - if len(args) > 0 and (args[0] is None or isinstance(args[0], QWidget)): - parent = args[0] - elif "parent" in kwargs: - parent = kwargs["parent"] - - if len(args) > 1: - window_flags = args[1] - elif "f" in kwargs: - window_flags = kwargs["f"] - - # Use default control if not set - if control is None: - control = self.CLSID - - # Call super init - QWidgetLogging.__init__(self, *args, **kwargs) - - # Create QAxWidget - self._control = control - self._ax = QAxWidget(self._control, self) - - # Check if instantiation of the QAxWidget was successful - successful = not self._ax.isNull() - if not successful: - raise RuntimeError( - "Requested control {} could not be instantiated".format(self._control) - ) - - # Initialize slot-like executor (for ensuring thread safety) - self._slot_like_executor = QSlotLikeExecutor(self) - - # Set methods as attributes - for method_name in self.METHOD_NAMES: - dynamic_callable = KiwoomOpenApiPlusDynamicCallable(self._ax, method_name) - dynamic_callable = self._slot_like_executor.wrapCallable(dynamic_callable) - setattr(self, method_name, dynamic_callable) - - # Set signals as attributes - for event_name in self.EVENT_NAMES: - signal_connector = KiwoomOpenApiPlusSignalConnector(event_name) - signal_connector.connect_to(self._ax) - setattr(self, event_name, signal_connector) - - # Call mixin init here, after method attributes are set - KiwoomOpenApiPlusQAxWidgetUniversalMixin.__init__(self) - - # Wrap additional mixin functions - self.CommRqDataWithInputs = self._slot_like_executor.wrapCallable( - self.CommRqDataWithInputs - ) - - # Call mixin init here, after method attributes are set - KiwoomOpenApiPlusQAxWidgetServerSideMixin.__init__(self) - - # Enable logging for QAxWidget exceptions - self._ax.exception.connect(self._onException) # pylint: disable=no-member - - # Enable logging for OpenAPI events - self._event_logger = KiwoomOpenApiPlusLoggingEventHandler(self) - self._event_logger.connect() - - # Other misc flags - self.hideOnMinimize = True - self.hideOnClose = True - - def _onException( - self, code, source, desc, help - ): # pylint: disable=redefined-builtin - self.logger.error("QAxBaseException(%r, %r, %r, %r)", code, source, desc, help) - - def __getattr__(self, name): - try: - # Fallback to AxObject for attrs such as 'self.dynamicCall(...)' - return getattr(self._ax, name) - except AttributeError as e: - raise AttributeError( - "'{}' object has no attribute '{}'".format( - self.__class__.__name__, name - ) - ) from e - - def changeEvent(self, event): - if event.type() == QEvent.WindowStateChange: - if self.windowState() & Qt.WindowMinimized: - if self.hideOnMinimize: - self.hide() - return event.ignore() - return event.accept() - - def closeEvent(self, event): - if self.hideOnClose: - self.hide() - return event.ignore() - return event.accept() diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.py deleted file mode 100644 index 0fb9d642..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin.py +++ /dev/null @@ -1,1297 +0,0 @@ -import json -import os -import queue -import subprocess - -from concurrent.futures import ThreadPoolExecutor -from pathlib import Path -from typing import Any, Callable, Dict, Mapping, Optional, Union, overload - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import ( - KiwoomOpenApiPlusDispatchFunctions, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter import ( - KiwoomOpenApiPlusCommRqDataRateLimiter, - KiwoomOpenApiPlusSendConditionRateLimiter, - KiwoomOpenApiPlusSendOrderRateLimiter, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, -) -from koapy.backend.kiwoom_open_api_plus.utils.list_conversion import string_to_list -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QRateLimitedExecutor import ( - QRateLimitedExecutor, -) -from koapy.config import config -from koapy.utils.ctypes import is_admin -from koapy.utils.logging import get_verbosity -from koapy.utils.logging.Logging import Logging -from koapy.utils.subprocess import Popen, function_to_subprocess_args - - -class KiwoomOpenApiPlusQAxWidgetUniversalMixin(KiwoomOpenApiPlusDispatchFunctions): - """ - 일차적으로 KiwoomOpenApiPlusQAxWidget 객체에 대해 사용될 수 있는 Mixin 이지만, - 넓게는 다른 KiwoomOpenApiPlusDispatchFunctions 인터페이스를 지원하는 모든 객체에서 사용될 수 있는, - 단순하면서도 유니버셜한 메소드들이 구현되어 있는 Mixin 입니다. - """ - - def IsConnected(self): - """ - 키움증권 서버에 접속되었는지 여부를 반환합니다. - """ - return self.GetConnectState() == 1 - - def ShowAccountWindow(self): - """ - 계좌 비밀번호 및 자동 로그인 처리 관련 설정창을 표시합니다. - """ - return self.KOA_Functions("ShowAccountWindow", "") - - def GetServerGubun(self): - """ - 접속된 서버의 종류를 확인해 구분값을 반환합니다. - """ - gubun = self.KOA_Functions("GetServerGubun", "") - if not gubun: - gubun = self.GetLoginInfo("GetServerGubun") - return gubun - - def IsSimulationServer(self): - """ - 모의투자 서버 접속 여부를 확인해 반환합니다. - """ - gubun = self.GetServerGubun() - return gubun == "1" - - def IsRealServer(self): - """ - 실 서버 접속 여부를 확인해 반환합니다. - """ - return not self.IsSimulationServer() - - def GetMasterStockInfo(self, code): - """ - 주식의 종목분류, 시장구분등의 정보를 제공합니다. - """ - return self.KOA_Functions("GetMasterStockInfo", code) - - def GetMasterStockInfoAsDict(self, code): - """ - 주식의 종목분류, 시장구분등의 정보를 딕셔너리 형태로 가공하여 제공합니다. - """ - result = self.GetMasterStockInfo(code) - items = string_to_list(result, sep=";") - items = [string_to_list(item, sep="|") for item in items] - info = dict(items) - return info - - def SetConditionSearchFlag(self, flag): - """ - 조건 검색시 동작과 관련된 플래그를 설정합니다. - """ - return self.KOA_Functions("SetConditionSearchFlag", flag) - - def AddPriceToConditionSearchResult(self): - """ - 조건 검색시 현재가를 함께 수신하도록 설정합니다. - """ - return self.SetConditionSearchFlag("AddPrice") - - def DelPriceFromConditionSearchResult(self): - """ - 조건 검색시 현재가를 함께 수신하지 않도록 설정합니다. - """ - return self.SetConditionSearchFlag("DelPrice") - - def GetStockMarketKind(self, code): - """ - 종목코드 입력으로 해당 종목이 어느 시장에 포함되어 있는지 구하는 기능입니다. - 서버와의 통신없이 메모리에 상주하는 값을 사용하므로 횟수제한 등은 없습니다. 사용법은 아래와 같습니다. - - 리턴값은 문자형으로 아래와 같습니다. - "0":코스피, "10":코스닥, "3":ELW, "8":ETF, "4"/"14":뮤추얼펀드, "6"/"16":리츠, "9"/"19":하이일드펀드, "30":제3시장, "60":ETN - """ - code = str(code) - return self.KOA_Functions("GetStockMarketKind", code) - - def GetUpjongCode(self, code): - """ - 업종코드 목록을 반환합니다. - - 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. - 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 - """ - code = str(code) - return self.KOA_Functions("GetUpjongCode", code) - - def GetUpjongCodeAsList(self, code): - """ - 업종코드 목록을 리스트 형태로 가공하여 반환합니다. - - 인자로 사용할 수 있는 값은 0, 1, 2, 4, 7 입니다. - 0:코스피, 1: 코스닥, 2:KOSPI200, 4:KOSPI100(KOSPI50), 7:KRX100 - """ - result = self.GetUpjongCode(code) - items = string_to_list(result, sep="|") - items = [string_to_list(item, sep=",") for item in items] - items = [tuple(item) for item in items] - return items - - def GetUpjongNameByCode(self, code): - """ - 주어진 업종코드의 이름을 반환합니다. - """ - return self.KOA_Functions("GetUpjongNameByCode", code) - - def IsOrderWarningETF(self, code): - """ - ETF 의 투자유의 종목 여부를 반환합니다. - - 투자유의 종목인 경우 "1" 값이 리턴, - 그렇지 않은 경우 "0" 값 리턴. - ETF가 아닌 종목을 입력시 "0" 값 리턴. - """ - return self.KOA_Functions("IsOrderWarningETF", code) - - def IsOrderWarningETFAsBoolean(self, code): - """ - ETF 의 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. - """ - return_code = self.IsOrderWarningETF(code) - return_code = int(return_code) - return_code = bool(return_code) - return return_code - - def IsOrderWarningStock(self, code): - """ - 주식 전종목 대상 투자유의 종목 여부를 반환합니다. - - 리턴 값 - "0":해당없음, "2":정리매매, "3":단기과열, "4":투자위험, "5":투자경고 - """ - return self.KOA_Functions("IsOrderWarningStock", code) - - def IsOrderWarningStockAsBoolean(self, code): - """ - 주식 전종목 대상 투자유의 종목 여부를 불리언 형태로 변환하여 반환합니다. - """ - return_code = self.IsOrderWarningStock(code) - return_code = int(return_code) - return_code = bool(return_code) - return return_code - - def GetMasterListedStockCntEx(self, code): - """ - 종목의 상장 주식수를 반환합니다. - - 기존의 GetMasterListedStockCnt() 함수 사용시 발생할 수 있는 오버플로우 문제를 해결합니다. - """ - return self.KOA_Functions("GetMasterListedStockCntEx", code) - - def GetMasterListedStockCntExAsInt(self, code): - """ - 종목의 상장 주식수를 정수 형태로 변환하여 반환합니다. - """ - count = self.GetMasterListedStockCntEx(code) - count = int(count) - return count - - def GetCodeListByMarketAsList(self, market: Optional[Union[str, int]] = None): - """ - 시장의 종목 코드 목록를 리스트 형태로 가공하여 반환합니다. - """ - if market is None: - market = "" - market = str(market) - result = self.GetCodeListByMarket(market) - result = string_to_list(result) - return result - - def GetNameListByMarketAsList(self, market: Optional[Union[str, int]] = None): - """ - 시장의 종목 이름 목록를 리스트 형태로 가공하여 반환합니다. - """ - codes = self.GetCodeListByMarketAsList(market) - names = [self.GetMasterCodeName(code) for code in codes] - return names - - def GetUserId(self): - """ - 사용자 ID 를 반환합니다. - """ - userid = self.GetLoginInfo("USER_ID") - return userid - - def GetUserName(self): - """ - 사용자 이름을 반환합니다. - """ - username = self.GetLoginInfo("USER_NAME") - return username - - def GetAccountCount(self): - """ - 계좌 개수를 반환합니다. - """ - account_count = self.GetLoginInfo("ACCOUNT_CNT") - account_count = int(account_count) - return account_count - - def GetAccountList(self): - """ - 계좌 목록을 리스트 형태로 가공하여 반환합니다. - """ - accounts = self.GetLoginInfo("ACCLIST") - accounts = string_to_list(accounts) - return accounts - - def GetKeyboardSecurityStatus(self): - """ - 키보드 보안 설정 상태를 반환합니다. - """ - return self.GetLoginInfo("KEY_BSECGB") - - def IsKeyboardSecurityEnabled(self): - """ - 키보드 보안 설정 상태를 불리언 형태로 변환하여 반환합니다. - """ - gubun = self.GetKeyboardSecurityStatus() - return gubun == "0" - - def GetFirewallStatus(self): - """ - 방화벽 설정 상태를 반환합니다. - """ - return self.GetLoginInfo("FIREW_SECGB") - - def IsFirewallEnabled(self): - """ - 방화벽 설정 상태를 불리언 형태로 변환하여 반환합니다. - """ - gubun = self.GetFirewallStatus() - return gubun == "1" - - def GetFirstAvailableAccount(self): - """ - 확인 가능한 첫번째 계좌번호를 반환합니다. - """ - account = None - accounts = self.GetAccountList() - if len(accounts) > 0: - account = accounts[0] - return account - - def GetMasterStockStateAsList(self, code: str): - """ - 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 - 리스트 형태로 가공하여 전달합니다. - """ - states = self.GetMasterStockState(code).strip() - states = string_to_list(states, sep="|") - return states - - def GetKospiCodeList(self): - """ - 장내 종목 코드 목록을 반환합니다. - """ - codes = self.GetCodeListByMarketAsList("0") - codes = sorted(codes) - return codes - - def GetKosdaqCodeList(self): - """ - 코스닥 시장내 종목 코드 목록을 반환합니다. - """ - codes = self.GetCodeListByMarketAsList("10") - codes = sorted(codes) - return codes - - def GetGeneralCodeList( - self, - include_preferred_stock: bool = False, - include_etn: bool = False, - include_etf: bool = False, - include_mutual_fund: bool = False, - include_reits: bool = False, - include_kosdaq: bool = False, - ): - """ - 장내 종목 코드 목록중 특정 그룹을 포함시키고 혹은 제거하고 반환합니다. - """ - - """ - [시장구분값] - 0 : 장내 - 10 : 코스닥 - 3 : ELW - 8 : ETF - 50 : KONEX - 4 : 뮤추얼펀드 - 5 : 신주인수권 - 6 : 리츠 - 9 : 하이얼펀드 - 30 : K-OTC - """ - - codes = self.GetKospiCodeList() - - # 코드 마지막 자리가 0 이 아니면 우선주일 가능성이 있다고 보고 제외 - if not include_preferred_stock: - codes = [code for code in codes if code.endswith("0")] - - # 장내 시장에서 ETN 이 섞여 있는데 시장구분값으로 뺄 수가 없어서 이름을 보고 대충 제외 - if not include_etn: - names = [self.GetMasterCodeName(code) for code in codes] - etn_suffixes = ["ETN", "ETN(H)", "ETN B", "ETN(H) B"] - is_not_etn_name = [ - not any(name.endswith(suffix) for suffix in etn_suffixes) - for name in names - ] - codes = [code for code, cond in zip(codes, is_not_etn_name) if cond] - - # 코드값 기준 제외 준비 - codes = set(codes) - - # 나머지는 혹시나 겹치는 애들이 나올 수 있는 시장에서 코드기준 제외 - if not include_kosdaq: - codes = codes - set(self.GetCodeListByMarketAsList("10")) # 코스닥 - if not include_etf: - codes = codes - set(self.GetCodeListByMarketAsList("8")) # ETF - if not include_mutual_fund: - codes = codes - set(self.GetCodeListByMarketAsList("4")) # 뮤추얼펀드 - if not include_reits: - codes = codes - set(self.GetCodeListByMarketAsList("6")) # 리츠 - - # 정렬된 리스트 형태로 제공 - codes = sorted(list(codes)) - - return codes - - def GetStockStates(self, code: str): - """ - 입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자유의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다. - """ - return self.GetMasterStockStateAsList(code) - - def GetSurveillanceFlag(self, code: str): - """ - 입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다. (정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목) - """ - return self.GetMasterConstruction(code) - - def IsSuspended(self, code: str): - """ - 거래정지 여부를 반환합니다. - """ - return "거래정지" in self.GetMasterStockStateAsList(code) - - def IsUnderSurveillance(self, code: str): - """ - 감리종목 여부를 반환합니다. - """ - return "감리종목" in self.GetMasterStockStateAsList(code) - - def IsUnderAdministration(self, code: str): - """ - 관리종목 여부를 반환합니다. - """ - return "관리종목" in self.GetMasterStockStateAsList(code) - - def IsFlaggedForCaution(self, code: str): - """ - 감리구분이 정상이 아니거나 상태값중 투자유의종목으로 지정된 경우 참을 반환합니다. - """ - flag = self.GetSurveillanceFlag(code) - states = self.GetMasterStockStateAsList(code) - flag_is_not_normal = flag != "정상" - has_caution_state = "투자유의종목" in states - return flag_is_not_normal or has_caution_state - - def IsNotNormal(self, code: str): - """ - 감리구분이 정상이 아니거나 상태값중 거래정지, 감리종목, 관리종목, 투자유의종목 등으로 지정된 경우 참을 반환합니다. - """ - flag = self.GetSurveillanceFlag(code) - states = self.GetMasterStockStateAsList(code) - flag_is_not_normal = flag != "정상" - bad_states = ["거래정지", "감리종목", "관리종목", "투자유의종목"] - has_any_bad_state = any(state in states for state in bad_states) - return flag_is_not_normal or has_any_bad_state - - def IsNormal(self, code: str): - """ - 감리구분이 정상이고 별다른 이상 상태값이 없는 경우 참을 반환합니다. - """ - return not self.IsNotNormal(code) - - def GetConditionFilePath(self): - """ - 조건식 데이터를 로드한 후 생성되는 조건검색 관련 데이터 파일의 경로를 반환합니다. - """ - module_path = self.GetAPIModulePath() - module_path = Path(module_path) - userid = self.GetUserId() - condition_filepath = module_path / "system" / f"{userid}_NewSaveIndex.dat" - condition_filepath = str(condition_filepath) - return condition_filepath - - def GetConditionNameListAsList(self): - """ - 조건식 데이터를 로드한 후 확인 가능한 조건식 목록을 리스트 형태로 가공하여 반환합니다. - """ - self.EnsureConditionLoaded() - conditions = self.GetConditionNameList() - conditions = string_to_list(conditions) - conditions = [string_to_list(cond, sep="^") for cond in conditions] - conditions = [(int(cond[0]), cond[1]) for cond in conditions] - return conditions - - def GetAutoLoginDatPath(self): - """ - 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일의 경로를 반환합니다. - """ - module_path = self.GetAPIModulePath() - module_path = Path(module_path) - autologin_dat = module_path / "system" / "Autologin.dat" - autologin_dat = str(autologin_dat) - return autologin_dat - - def IsAutoLoginEnabled(self): - """ - 자동 로그인 설정 여부를 반환합니다. - - 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는지의 여부를 확인합니다. - """ - autologin_dat = self.GetAutoLoginDatPath() - return os.path.exists(autologin_dat) - - def DisableAutoLogin(self): - """ - 자동 로그인 설정을 해제합니다. - - 자동 로그인 설정시 생성되는 자동 로그인 관련 데이터 파일 경로에 파일이 존재하는 경우 해당 파일을 삭제합니다. - """ - autologin_dat = self.GetAutoLoginDatPath() - if os.path.exists(autologin_dat): - os.remove(autologin_dat) - - def CommRqDataWithInputs( - self, - rqname: str, - trcode: str, - prevnext: int, - scrnno: str, - inputs: Optional[Dict[str, str]] = None, - ) -> int: - """ - CommRqData() 호출 이전에 주어진 입력값들로 SetInputValue() 호출을 통한 입력값 설정을 진행합니다. - 이후 CommRqData() 를 호출합니다. - """ - # lookup tr_info for the given code - tr_info = KiwoomOpenApiPlusTrInfo.of(trcode) - # if found, - if tr_info: - # set in order because input order matters here - # will incur OnReceiveMsg('', '', '', 'Fail to parse Request TR') if it goes wrong - for tr_input in tr_info.inputs: - input_name = tr_input.name - input_value = inputs[input_name] - self.SetInputValue(input_name, input_value) - # if not found but inputs are given, - elif inputs: - # fallback to default behavior if tr_info is not found - for input_name, input_value in inputs.items(): - self.SetInputValue(input_name, input_value) - # ensure prevnext is int - prevnext = int(prevnext) - code = self.CommRqData(rqname, trcode, prevnext, scrnno) - return code - - # ====================================================================== - - @classmethod - def RunScriptInSubprocess_WithData( - cls, - main: Callable[..., Any], - data: Optional[Mapping[str, Any]] = None, - wait: bool = False, - timeout: bool = None, - check: bool = False, - stdin: Optional[int] = subprocess.PIPE, - stdout: Optional[int] = None, - ): - args = function_to_subprocess_args(main) - process = Popen(args, stdin=stdin, stdout=stdout, text=True) - json.dump(data, process.stdin) - - if wait: - try: - stdout, stderr = process.communicate(timeout=timeout) - except subprocess.TimeoutExpired as exc: - process.kill() - exc.stdout, exc.stderr = process.communicate() - raise exc - except: - process.kill() - raise - retcode = process.poll() - completed = subprocess.CompletedProcess( - process.args, retcode, stdout, stderr - ) - if check: - completed.check_returncode() - return completed - - return process - - @classmethod - def LoginUsingPywinauto_Impl(cls, credentials: Optional[Mapping[str, Any]] = None): - import pywinauto - - if credentials is None: - credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") - - is_in_development = False - emulate_keyboard_input = True - - userid = credentials.get("user_id") - password = credentials.get("user_password") - cert = credentials.get("cert_password") - - is_save_userid = True - is_simulation = credentials.get("is_simulation") - - desktop = pywinauto.Desktop(allow_magic_lookup=False) - login_window = desktop.window(title="Open API Login") - - try: - cls.logger.info("Waiting for login screen") - timeout_login_screen_ready = 30 - login_window.wait("ready", timeout_login_screen_ready) - except pywinauto.timings.TimeoutError: - cls.logger.info("Cannot find login screen") - raise - else: - cls.logger.info("Login screen found") - if is_in_development: - login_window.print_control_identifiers() - - if userid: - cls.logger.info("Putting userid") - if emulate_keyboard_input: - login_window["Edit1"].set_focus() - pywinauto.keyboard.send_keys(userid) - pywinauto.keyboard.send_keys("{TAB}") - else: - login_window["Edit1"].set_text(userid) - if password: - cls.logger.info("Putting password") - if emulate_keyboard_input: - login_window["Edit2"].set_focus() - pywinauto.keyboard.send_keys(password) - pywinauto.keyboard.send_keys("{TAB}") - else: - login_window["Edit2"].set_text(password) - else: - raise RuntimeError("'user_password' not set, please check credentials") - - if is_save_userid: - cls.logger.info("Checking to save userid") - login_window["Button6"].check() # check doesn't work - else: - cls.logger.info("Unchecking to save userid") - login_window["Button6"].uncheck() # uncheck doesn't work - - if not is_simulation: - if not login_window["Edit3"].is_enabled(): - cls.logger.info("Unchecking to use simulation server") - if emulate_keyboard_input: - login_window["Button5"].set_focus() - pywinauto.keyboard.send_keys("{SPACE}") - else: - login_window["Button5"].uncheck_by_click() - - if cert: - cls.logger.info("Putting cert password") - if emulate_keyboard_input: - login_window["Edit3"].set_focus() - pywinauto.keyboard.send_keys(cert) - pywinauto.keyboard.send_keys("{TAB}") - else: - login_window["Edit3"].set_text(cert) - else: - raise RuntimeError( - "'cert_password' not set, please check credentials" - ) - else: - if login_window["Edit3"].is_enabled(): - cls.logger.info("Checking to use simulation server") - if emulate_keyboard_input: - login_window["Button5"].set_focus() - pywinauto.keyboard.send_keys("{SPACE}") - else: - login_window["Button5"].check_by_click() - - cls.logger.info("Logging in") - login_window["Button1"].click() - - @classmethod - def LoginUsingPywinauto_RunScriptInSubprocess( - cls, - credentials: Optional[Mapping[str, Any]] = None, - wait: bool = False, - timeout: bool = None, - check: bool = False, - ): - def main(): - # pylint: disable=redefined-outer-name,reimported,import-self - import json - import sys - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetMixin, - ) - from koapy.utils.logging import set_verbosity - - data = json.load(sys.stdin) - credentials = data["credentials"] - verbosity = data["verbosity"] - set_verbosity(verbosity) - KiwoomOpenApiPlusQAxWidgetMixin.LoginUsingPywinauto_Impl(credentials) - - verbosity = get_verbosity() - data = { - "credentials": credentials, - "verbosity": verbosity, - } - - return cls.RunScriptInSubprocess_WithData( - main, - data, - wait=wait, - timeout=timeout, - check=check, - ) - - def LoginUsingPywinauto( - self, - credentials: Optional[Mapping[str, Any]] = None, - wait: bool = True, - timeout: bool = None, - check: bool = True, - ): - """ - 자식 프로세스 내에서 pywinauto 를 사용해 로그인 처리를 자동으로 진행합니다. - """ - assert is_admin(), "Using pywinauto requires administrator permission" - return self.LoginUsingPywinauto_RunScriptInSubprocess( - credentials, - wait=wait, - timeout=timeout, - check=check, - ) - - @overload - def CommConnectAndThen( - self, - credentials: Mapping[str, Any], - callback: Callable[[int], Any], - ) -> int: - ... - - @overload - def CommConnectAndThen(self, credentials: Mapping[str, Any]) -> int: - ... - - @overload - def CommConnectAndThen(self, callback: Callable[[int], Any]) -> int: - ... - - @overload - def CommConnectAndThen(self) -> int: - ... - - def CommConnectAndThen( - self, - credentials_or_callback=None, - callback_or_none=None, - ) -> int: - """ - 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 특정 콜백 함수를 실행합니다. - """ - credentials = credentials_or_callback - callback = callback_or_none - - if ( - callback is None - and credentials is not None - and not isinstance(credentials, dict) - and callable(credentials) - ): - callback = credentials - credentials = None - - can_use_pywinauto = is_admin() - should_use_pywinauto = credentials is not None - - if should_use_pywinauto: - assert ( - can_use_pywinauto - ), "CommConnectAndThen() method requires to be run as administrator if credentials argument was given explicitly" - - if should_use_pywinauto: - self.DisableAutoLogin() - - if credentials is None and not self.IsAutoLoginEnabled() and can_use_pywinauto: - credentials = config.get( - key="koapy.backend.kiwoom_open_api_plus.credentials", - default=None, - ) - should_use_pywinauto = credentials is not None - - def OnEventConnect(errcode): - self.OnEventConnect.disconnect(OnEventConnect) - if callable(callback): - callback(errcode) - - self.OnEventConnect.connect(OnEventConnect) - errcode = KiwoomOpenApiPlusError.try_or_raise(self.CommConnect()) - - if should_use_pywinauto and not self.IsAutoLoginEnabled(): - self.LoginUsingPywinauto(credentials, wait=False) - - return errcode - - def Connect(self, credentials: Optional[Mapping[str, Any]] = None) -> int: - """ - 로그인 처리를 진행하고 이후 발생하는 이벤트 함수내에서 확인 가능한 에러코드 값을 반환합니다. - """ - q = queue.Queue() - - def OnEventConnect(errcode): - q.put(errcode) - - errcode = self.CommConnectAndThen(credentials, OnEventConnect) - errcode = KiwoomOpenApiPlusError.try_or_raise(q.get()) - - return errcode - - @overload - def EnsureConnectedAndThen( - self, - credentials: Mapping[str, Any], - callback: Callable[[int], Any], - ) -> bool: - ... - - @overload - def EnsureConnectedAndThen(self, credentials: Mapping[str, Any]) -> bool: - ... - - @overload - def EnsureConnectedAndThen(self, callback: Callable[[int], Any]) -> bool: - ... - - @overload - def EnsureConnectedAndThen(self) -> bool: - ... - - def EnsureConnectedAndThen( - self, - credentials_or_callback=None, - callback_or_none=None, - ) -> bool: - """ - 로그인 여부를 확인하고 로그인 상태를 보장한 뒤에 주어진 콜백 함수를 실행합니다. - - 로그인 여부 확인시 로그인 되어있지 않다면 로그인을 진행한 뒤 주어진 콜백 함수를 실행합니다. - 이미 로그인이 되어있다면 즉시 주어진 콜백 함수를 실행합니다. - """ - credentials = credentials_or_callback - callback = callback_or_none - - if ( - callback is None - and credentials is not None - and not isinstance(credentials, dict) - and callable(credentials) - ): - callback = credentials - credentials = None - - is_connected = self.IsConnected() - - if not is_connected: - - def OnEventConnect(errcode): - if errcode == 0: - if callable(callback): - callback(errcode) - - errcode = self.CommConnectAndThen(credentials, OnEventConnect) - else: - if callable(callback): - errcode = 0 - callback(errcode) - - return is_connected - - def EnsureConnected(self, credentials: Optional[Mapping[str, Any]] = None) -> bool: - """ - 로그인 상태를 보장하도록 합니다. - - 이미 로그인이 되어있는 경우 별다른 처리를 하지 않습니다. - 로그인이 되어있지 않다면 로그인을 수행합니다. - """ - is_connected = self.IsConnected() - if not is_connected: - self.Connect(credentials) - is_connected = self.IsConnected() - assert is_connected, "Could not ensure connected" - return is_connected - - @classmethod - def EnableAutoLoginUsingPywinauto_Impl( - cls, account_passwords: Optional[Mapping[str, Any]] = None - ): - import pywinauto - - if account_passwords is None: - credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") - account_passwords = credentials.get("account_passwords") - - account_passwords = dict(account_passwords) - - is_in_development = False - - desktop = pywinauto.Desktop(allow_magic_lookup=False) - account_window = desktop.window(title_re=r"계좌비밀번호 입력 \(버전: [0-9]+.+[0-9]+\)") - - try: - cls.logger.info("Waiting for account window to show up") - timeout_account_window_ready = 15 - account_window.wait("ready", timeout_account_window_ready) - except pywinauto.timings.TimeoutError: - cls.logger.info("Cannot find account window") - raise - else: - cls.logger.info("Account window found") - if is_in_development: - account_window.print_control_identifiers() - - cls.logger.info("Enabling auto login") - account_window["CheckBox"].check() - - account_combo = account_window["ComboBox"] - account_cnt = account_combo.item_count() - - cls.logger.info("Putting account passwords") - for i in range(account_cnt): - account_combo.select(i) - account_no = account_combo.selected_text().split()[0] - if account_pw := account_passwords.get( - account_no - ) or account_passwords.get("0000000000"): - account_window["Edit"].set_text(account_pw) - account_window["등록"].click() - - cls.logger.info("Closing account window") - account_window["닫기"].click() - - try: - cls.logger.info("Waiting account window to be closed") - timeout_account_window_done = 5 - account_window.wait_not("visible", timeout_account_window_done) - except pywinauto.timings.TimeoutError as e: - cls.logger.info("Cannot sure account window is closed") - raise RuntimeError("Cannot sure account window is closed") from e - else: - cls.logger.info("Account window closed") - - @classmethod - def EnableAutoLoginUsingPywinauto_RunScriptInSubprocess( - cls, - account_passwords: Optional[Mapping[str, Any]] = None, - wait: bool = False, - timeout: bool = None, - check: bool = False, - ): - def main(): - # pylint: disable=redefined-outer-name,reimported,import-self - import json - import sys - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetMixin, - ) - from koapy.utils.logging import set_verbosity - - data = json.load(sys.stdin) - account_passwords = data["account_passwords"] - verbosity = data["verbosity"] - set_verbosity(verbosity) - KiwoomOpenApiPlusQAxWidgetMixin.EnableAutoLoginUsingPywinauto_Impl( - account_passwords - ) - - verbosity = get_verbosity() - data = { - "account_passwords": account_passwords, - "verbosity": verbosity, - } - - return cls.RunScriptInSubprocess_WithData( - main, - data, - wait=wait, - timeout=timeout, - check=check, - ) - - def EnableAutoLoginUsingPywinauto( - self, - credentials: Optional[Mapping[str, Any]] = None, - wait: bool = True, - timeout: bool = None, - check: bool = True, - ): - """ - 자식 프로세스 내에서 pywinauto 를 사용해 자동 로그인 설정을 자동으로 진행합니다. - """ - assert is_admin(), "Using pywinauto requires administrator permission" - return self.EnableAutoLoginUsingPywinauto_RunScriptInSubprocess( - credentials, - wait=wait, - timeout=timeout, - check=check, - ) - - def EnableAutoLogin(self, credentials: Optional[Mapping[str, Any]] = None): - """ - 자동 로그인을 설정합니다. - """ - q = queue.Queue() - - def callback(errcode): - with ThreadPoolExecutor(1) as executor: - future = executor.submit(self.ShowAccountWindow) - self.EnableAutoLoginUsingPywinauto(credentials) - future.result() - q.put(errcode) - - self.EnsureConnectedAndThen(credentials, callback) - errcode = KiwoomOpenApiPlusError.try_or_raise(q.get()) - is_enabled = self.IsAutoLoginEnabled() - return is_enabled - - def EnsureAutoLoginEnabled( - self, credentials: Optional[Mapping[str, Any]] = None - ) -> bool: - """ - 자동 로그인이 설정되어 있음을 보장하도록 합니다. - - 이미 자동 로그인이 설정 되어있는 경우 별다른 처리를 하지 않습니다. - 자동 로그인이 설정되어 있지 않다면 자동 로그인을 설정을 처리합니다. - """ - is_enabled = self.IsAutoLoginEnabled() - if not is_enabled: - self.EnableAutoLogin(credentials) - is_enabled = self.IsAutoLoginEnabled() - assert is_enabled, "Could not ensure auto login enabled" - return is_enabled - - @classmethod - def HandleVersionUpgradeUsingPywinauto_Impl(cls, pid): - import psutil - import pywinauto - - desktop = pywinauto.Desktop(allow_magic_lookup=False) - login_window = desktop.window(title="Open API Login") - - timeout_login_successful = 4 - timeout_version_check = 1 - timeout_per_trial = timeout_login_successful + timeout_version_check - - trial_timeout = 180 - trial_count = trial_timeout / timeout_per_trial - - while trial_count > 0: - try: - cls.logger.info( - "Login in progress ... timeout after %d sec", - trial_count * timeout_per_trial, - ) - trial_count -= 1 - login_window.wait_not("exists", timeout_login_successful) - if login_window.exists(): - # make sure that login_window control does not exist. - continue - except pywinauto.timings.TimeoutError as e: - version_window = desktop.window(title="opstarter") - try: - version_window.wait("ready", timeout_version_check) - except pywinauto.timings.TimeoutError: - continue - else: - cls.logger.info("Version update required") - - cls.logger.info("Closing login app") - login_window_proc = psutil.Process(pid) - login_window_proc.kill() - login_window_proc.wait() - cls.logger.info("Killed login app process") - timeout_login_screen_closed = 30 - login_window.close(timeout_login_screen_closed) - try: - login_window.wait_not("visible", timeout_login_screen_closed) - except pywinauto.timings.TimeoutError as e: - cls.logger.warning("Cannot close login window") - raise RuntimeError("Cannot close login window") from e - else: - cls.logger.info("Closed login window") - - cls.logger.info("Starting to update version") - version_window["Button"].click() - - versionup_window = desktop.window(title="opversionup") - confirm_window = desktop.window(title="업그레이드 확인") - - try: - cls.logger.info("Waiting for possible failure") - timeout_confirm_update = 10 - versionup_window.wait("ready", timeout_confirm_update) - except pywinauto.timings.TimeoutError: - cls.logger.info("Cannot find failure confirmation popup") - else: - cls.logger.warning("Failed to update") - raise RuntimeError("Failed to update") from e - - try: - cls.logger.info( - "Waiting for confirmation popup after update" - ) - timeout_confirm_update = 10 - confirm_window.wait("ready", timeout_confirm_update) - except pywinauto.timings.TimeoutError as e: - cls.logger.warning("Cannot find confirmation popup") - raise RuntimeError("Cannot find confirmation popup") from e - else: - cls.logger.info("Confirming update") - confirm_window["Button"].click() - - cls.logger.info("Done update") - return True - else: - cls.logger.info("Login ended successfully") - cls.logger.info("No version update required") - return False - return False - - @classmethod - def HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess( - cls, - pid: int, - wait: bool = False, - timeout: bool = None, - check: bool = False, - ): - def main(): - # pylint: disable=redefined-outer-name,reimported,import-self - import json - import sys - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetMixin, - ) - from koapy.utils.logging import set_verbosity - - data = json.load(sys.stdin) - pid = data["pid"] - verbosity = data["verbosity"] - set_verbosity(verbosity) - is_updated = ( - KiwoomOpenApiPlusQAxWidgetMixin.HandleVersionUpgradeUsingPywinauto_Impl( - pid - ) - ) - result = {"is_updated": is_updated} - json.dump(result, sys.stdout) - - verbosity = get_verbosity() - data = { - "pid": pid, - "verbosity": verbosity, - } - - completed = cls.RunScriptInSubprocess_WithData( - main, - data, - wait=wait, - timeout=timeout, - check=check, - stdout=subprocess.PIPE, - ) - result = json.loads(completed.stdout) - is_updated = result["is_updated"] - return is_updated - - def HandleVersionUpgradeUsingPywinauto( - self, - pid: int, - wait: bool = True, - timeout: bool = None, - check: bool = True, - ): - """ - 자식 프로세스 내에서 pywinauto 를 사용해 버전 업그레이드 처리를 자동으로 진행합니다. - """ - assert is_admin(), "Using pywinauto requires administrator permission" - return self.HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess( - pid, - wait=wait, - timeout=timeout, - check=check, - ) - - -class KiwoomOpenApiPlusQAxWidgetServerSideMixin( - KiwoomOpenApiPlusDispatchFunctions, Logging -): - """ - KiwoomOpenApiPlusQAxWidget 객체에 대해 Server-Side 에서만 사용되는 Mixin 입니다. - - 주로 서버 환경에서만 확인하거나 처리가 가능한 아래 기능들을 커버합니다: - - - 조건검색식 로드 - - 조회 횟수 제한 회피 기능 - """ - - def __init__(self): - """ - 조건검색식 로드 및 조회 횟수 제한 회피 기능 관련 초기화를 진행합니다. - """ - - """ - [OpenAPI 게시판] - https://www.kiwoom.com/h/common/bbs/VBbsBoardBWOAZView - - [조회횟수 제한 관련 가이드] - - 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기 - - 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기 - - 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기 - """ - - """ - [조회제한] - OpenAPI 조회는 1초당 5회로 제한되며 복수종목 조회와 조건검색 조회 횟수가 합산됩니다. - 가령 1초 동안 시세조회2회 관심종목 1회 조건검색 2회 순서로 조회를 했다면 모두 합쳐서 5회이므로 모두 조회성공하겠지만 - 조건검색을 3회 조회하면 맨 마지막 조건검색 조회는 실패하게 됩니다. - - [조건검색 제한] - 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다. - """ - - self._comm_rate_limiter = KiwoomOpenApiPlusCommRqDataRateLimiter() - self._cond_rate_limiter = KiwoomOpenApiPlusSendConditionRateLimiter( - self._comm_rate_limiter - ) - self._order_rate_limiter = KiwoomOpenApiPlusSendOrderRateLimiter() - - self._comm_rate_limited_executor = QRateLimitedExecutor( - self._comm_rate_limiter, self - ) - self._cond_rate_limited_executor = QRateLimitedExecutor( - self._cond_rate_limiter, self - ) - self._order_rate_limited_executor = QRateLimitedExecutor( - self._order_rate_limiter, self - ) - - self.RateLimitedCommRqData = self._comm_rate_limited_executor.wrapCallable( - self.CommRqDataWithInputs - ) - self.RateLimitedCommKwRqData = self._comm_rate_limited_executor.wrapCallable( - self.CommKwRqData - ) - self.RateLimitedSendCondition = self._cond_rate_limited_executor.wrapCallable( - self.SendCondition - ) - self.RateLimitedSendOrder = self._order_rate_limited_executor.wrapCallable( - self.SendOrder - ) - - self._is_condition_loaded = False - - self._comm_rate_limited_executor.start() - self._cond_rate_limited_executor.start() - self._order_rate_limited_executor.start() - - self.destroyed.connect(self._comm_rate_limited_executor.shutdown) - self.destroyed.connect(self._cond_rate_limited_executor.shutdown) - self.destroyed.connect(self._order_rate_limited_executor.shutdown) - - def LoadCondition(self) -> int: - """ - 조건검색 관련 조건식을 불러옵니다. - """ - q = queue.Queue() - - def OnReceiveConditionVer(ret, msg): - if not ret: - q.put(KiwoomOpenApiPlusError(msg)) - else: - q.put((ret, msg)) - - self.OnReceiveConditionVer.connect(OnReceiveConditionVer) - try: - return_code = KiwoomOpenApiPlusError.try_or_raise_boolean( - self.GetConditionLoad(), "Failed to load condition" - ) - res = q.get() - if isinstance(res, KiwoomOpenApiPlusError): - raise res - except: # pylint: disable=try-except-raise - raise - else: - if return_code == 1: - self._is_condition_loaded = True - finally: - self.OnReceiveConditionVer.disconnect(OnReceiveConditionVer) - return return_code - - def IsConditionLoaded(self) -> bool: - """ - 조건식이 로드 되었는지 여부를 반환합니다. - """ - # the original implementation of this function was like the following: - # condition_filepath = self.GetConditionFilePath() - # return os.path.exists(condition_filepath) - return self._is_condition_loaded - - def EnsureConditionLoaded(self, force: bool = False) -> int: - """ - 조건식이 로드됨을 보장하도록 합니다. - - 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. - 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. - """ - return_code = 0 - is_condition_loaded = self.IsConditionLoaded() - if not is_condition_loaded or force: - return_code = self.LoadCondition() - else: - return_code = 1 - assert return_code == 1, "Could not ensure condition loaded" - return return_code - - -class KiwoomOpenApiPlusQAxWidgetMixin( - KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin -): - """ - KiwoomOpenApiPlusQAxWidgetUniversalMixin, KiwoomOpenApiPlusQAxWidgetServerSideMixin 구현이 포함된 - KiwoomOpenApiPlusQAxWidget 객체를 위한 Mixin 입니다. - """ diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.py deleted file mode 100644 index 0e4f62e2..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter.py +++ /dev/null @@ -1,103 +0,0 @@ -import threading -import time - -from koapy.utils.rate_limiting.RateLimiter import ( - CompositeTimeWindowRateLimiter, - RateLimiter, - TimeWindowRateLimiter, -) - - -class KiwoomOpenApiPlusCommRqDataRateLimiter(CompositeTimeWindowRateLimiter): - - # [조회횟수 제한 관련] - # 단순하게 1초당 5회로 날리다보면 장기적으로 결국 막히기 때문에 기존에는 4초당 1회로 제한했었음 (3초당 1회부턴 제한걸림) - # 이후 1시간에 1000회로 제한한다는 추측이 있는데 일리 있어 보여서 도입 (http://blog.quantylab.com/htsapi.html) - # 1초당 1회로 계산했을때 1시간이면 3600 회, 주기를 1초씩 늘려보면 - # 2초당 1회 => 1800 > 1000, 3초당 1회 => 1200 > 1000, 4초당 1회 => 900 < 1000 - - """ - [조회횟수 제한 관련 가이드] - - 1초당 5회 조회를 1번 발생시킨 경우 : 17초대기 - - 1초당 5회 조회를 5연속 발생시킨 경우 : 90초대기 - - 1초당 5회 조회를 10연속 발생시킨 경우 : 3분(180초)대기 - """ - - def __init__(self): - limiters = [ - TimeWindowRateLimiter(18, 5), - TimeWindowRateLimiter(90, 25), - TimeWindowRateLimiter(180, 50), - TimeWindowRateLimiter(3600, 1000), - ] - super().__init__(limiters) - - -class KiwoomOpenApiPlusSendOrderRateLimiter(TimeWindowRateLimiter): - def __init__(self): - super().__init__(1, 5) - - -class KiwoomOpenApiPlusSendConditionRateLimiter(RateLimiter): - # pylint: disable=arguments-differ - - """ - [조건검색 제한] - - 조건검색(실시간 조건검색 포함)은 시세조회와 관심종목조회와 합산해서 1초에 5회만 요청 가능하며 1분에 1회로 조건검색 제한됩니다. - - [조건검색 제한] - 조건검색 요청은 1초당 5회 조회횟수 제한에 포함됩니다. - 동일 조건식에 대한 조건검색 요청은 1분에 1회로 제한됩니다. - 조건검색 결과가 100종목을 넘게 되면 해당조건은 실시간 조건검색 신호를 수신할 수 없습니다. - 실시간 조건검색은 최대 10개까지 사용 가능합니다. - """ - - def __init__(self, comm_rate_limiter): - self._lock = threading.RLock() - - self._comm_rate_limiter = comm_rate_limiter - self._limiters_per_condition = {} - - def get_limiter_per_condition(self, condition_name, condition_index): - limiter_key = (condition_name, condition_index) - if limiter_key not in self._limiters_per_condition: - self._limiters_per_condition[limiter_key] = TimeWindowRateLimiter(60, 1) - limiter_per_condition = self._limiters_per_condition[limiter_key] - return limiter_per_condition - - def check_sleep_seconds(self, fn, *args, **kwargs): - condition_name = None - condition_index = None - if fn.__name__ == "SendCondition": - condition_name = kwargs.get("condition_name", args[1]) - condition_index = kwargs.get("condition_index", args[2]) - with self._lock: - sleep_seconds = self._comm_rate_limiter.check_sleep_seconds() - if condition_name is not None and condition_index is not None: - limiter_per_condition = self.get_limiter_per_condition( - condition_name, condition_index - ) - sleep_seconds = max( - sleep_seconds, limiter_per_condition.check_sleep_seconds() - ) - return sleep_seconds - - def add_call_history(self, fn, *args, **kwargs): - condition_name = None - condition_index = None - if fn.__name__ == "SendCondition": - condition_name = kwargs.get("condition_name", args[1]) - condition_index = kwargs.get("condition_index", args[2]) - with self._lock: - self._comm_rate_limiter.add_call_history() - if condition_name is not None and condition_index is not None: - limiter_per_condition = self.get_limiter_per_condition( - condition_name, condition_index - ) - limiter_per_condition.add_call_history() - - def sleep_if_necessary(self, fn, *args, **kwargs): - with self._lock: - sleep_seconds = self.check_sleep_seconds(fn, *args, **kwargs) - if sleep_seconds > 0: - time.sleep(sleep_seconds) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.py deleted file mode 100644 index 3801fae7..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType.py +++ /dev/null @@ -1,338 +0,0 @@ -from __future__ import annotations - -import contextlib -import json - -from os import PathLike -from pathlib import Path -from typing import BinaryIO, Dict, List, Optional, TextIO, Union - -import pandas as pd - -from koapy.config import debug, default_encoding -from koapy.utils.logging.Logging import Logging -from koapy.utils.serialization import JsonSerializable - - -class KiwoomOpenApiPlusRealType(JsonSerializable, Logging): - class Fid(JsonSerializable): - - __outer_class__ = None - - FID_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata" - FID_DUMP_FILENAME = "fid.csv" - FID_DUMP_FILEPATH = FID_DUMP_FILEDIR / FID_DUMP_FILENAME - FID_DUMP_PROCESSOR = pd.read_csv - - FID_BY_FID: Dict[int, KiwoomOpenApiPlusRealType.Fid] = {} - FID_BY_NAME: Dict[str, KiwoomOpenApiPlusRealType.Fid] = {} - - def __init__(self, fid: Optional[int] = None, name: Optional[str] = None): - if fid is not None and name is None: - name = self.get_name_by_fid(fid) - self.fid = fid - self.name = name - - def __repr__(self): - return "{}.{}({!r}, {!r})".format( - self.__outer_class__.__name__, - self.__class__.__name__, - self.fid, - self.name, - ) - - def __eq__(self, other): - if isinstance(other, type(self)): - return self.fid == other.fid and self.name == other.name - return False - - @classmethod - def fids_from_dump_file( - cls, - dump_file: Optional[Union[str, PathLike]] = None, - encoding: Optional[str] = None, - ) -> Dict[int, str]: - if dump_file is None: - dump_file = cls.FID_DUMP_FILEPATH - if encoding is None: - encoding = "utf-8" - df = cls.FID_DUMP_PROCESSOR(dump_file, encoding=encoding) - fids = [cls(pair[0], pair[1]) for pair in zip(df["fid"], df["name"])] - return fids - - @classmethod - def load_from_dump_file(cls, dump_file: Optional[Union[str, PathLike]] = None): - fids = cls.fids_from_dump_file(dump_file) - cls.FID_BY_FID = {fid.fid: fid for fid in fids} - cls.FID_BY_NAME = {fid.name: fid for fid in fids} - - @classmethod - def from_fid( - cls, fid: Union[str, int] - ) -> Optional[KiwoomOpenApiPlusRealType.Fid]: - fid = int(fid) - fid = cls.FID_BY_FID.get(fid) - return fid - - @classmethod - def from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType.Fid]: - fid = cls.FID_BY_NAME.get(name) - return fid - - @classmethod - def get_name_by_fid( - cls, fid: Union[str, int], default: Optional[str] = None - ) -> Optional[str]: - fid = cls.from_fid(fid) - return fid.name if fid else default - - REALTYPE_BY_DESC_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata" - REALTYPE_BY_DESC_DUMP_FILENAME = "realtype_by_desc.json" - REALTYPE_BY_DESC_DUMP_FILEPATH = ( - REALTYPE_BY_DESC_DUMP_FILEDIR / REALTYPE_BY_DESC_DUMP_FILENAME - ) - - REALTYPE_BY_DESC: Dict[str, KiwoomOpenApiPlusRealType] = {} - - def __init__( - self, - gidc: Optional[str] = None, - desc: Optional[str] = None, - nfid: Optional[int] = None, - fids: Optional[List[int]] = None, - ): - self.gidc = gidc - self.desc = desc - self.nfid = nfid - self.fids = fids - - def __repr__(self): - return "{}({!r}, {!r}, {!r}, {!r})".format( - self.__class__.__name__, - self.gidc, - self.desc, - self.nfid, - self.fids, - ) - - def __eq__(self, other): - if isinstance(other, type(self)): - return ( - self.gidc == other.gidc - and self.desc == other.desc - and self.nfid == other.nfid - and self.fids == other.fids - ) - return False - - @classmethod - def get_realtype_name_list(cls): - return list(cls.REALTYPE_BY_DESC.keys()) - - @classmethod - def get_realtype_info_list(cls): - return list(cls.REALTYPE_BY_DESC.values()) - - @classmethod - def get_realtype_info_by_desc( - cls, desc: str - ) -> Optional[KiwoomOpenApiPlusRealType]: - return cls.REALTYPE_BY_DESC.get(desc) - - @classmethod - def get_realtype_info_by_name( - cls, name: str - ) -> Optional[KiwoomOpenApiPlusRealType]: - return cls.get_realtype_info_by_desc(name) - - @classmethod - def get_realtype_info_by_realtype_name( - cls, name: str - ) -> Optional[KiwoomOpenApiPlusRealType]: - return cls.get_realtype_info_by_name(name) - - @classmethod - def from_name(cls, name: str) -> Optional[KiwoomOpenApiPlusRealType]: - return cls.get_realtype_info_by_name(name) - - @classmethod - def get_fids_by_realtype_name(cls, name: str) -> Optional[List[int]]: - result = cls.get_realtype_info_by_realtype_name(name) - if result is not None: - return result.fids - return None - - @classmethod - def get_fids_by_realtype_name_as_string(cls, name: str) -> Optional[str]: - fids = cls.get_fids_by_realtype_name(name) - if fids is not None: - fids = [str(fid) for fid in fids] - fids = ";".join(fids) - return fids - - @classmethod - def get_field_names_by_realtype_name(cls, name: str) -> Optional[List[str]]: - fids = cls.get_fids_by_realtype_name(name) - names = None - if fids is not None: - names = [cls.Fid.get_name_by_fid(fid, str(fid)) for fid in fids] - return names - - @classmethod - def realtypes_from_datfile( - cls, - dat_file: Optional[Union[str, PathLike, BinaryIO]] = None, - encoding: Optional[str] = None, - module_path: Optional[str] = None, - ) -> List[KiwoomOpenApiPlusRealType]: - if dat_file is None: - if module_path is None: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - module_path = API_MODULE_PATH - dat_file = module_path / "data" / "nkrealtime.dat" - - if isinstance(dat_file, str): - dat_file = Path(dat_file) - - if encoding is None: - encoding = "euc-kr" - - gidc_width = 2 - desc_width = 20 - nfid_width = 3 - fid_width = 5 - - with contextlib.ExitStack() as stack: - if isinstance(dat_file, Path): - if debug: - cls.logger.debug("Reading file %s", dat_file) - dat_file = open(dat_file, "rb") - dat_file = stack.enter_context(dat_file) - lines = iter(dat_file) - lines = map(lambda line: line.rstrip(b"\r\n"), lines) - lines = filter(lambda line: not line.startswith(b";"), lines) - realtypes = [] - for line in lines: - gidc = line[:gidc_width] - line = line[gidc_width:] - gidc = gidc.decode(encoding).strip() - desc = line[:desc_width] - line = line[desc_width:] - desc = desc.decode(encoding).strip() - nfid = line[:nfid_width] - nfid = nfid.strip() - line = line[nfid_width:] - if len(nfid) > 0: - nfid = int(nfid) - else: - nfid = 0 - fids = [] - for _ in range(nfid): - fid = line[:fid_width] - line = line[fid_width:] - fid = int(fid) - fids.append(fid) - assert len(line.rstrip(b"^M ")) == 0 - realtypes.append(cls(gidc, desc, nfid, fids)) - return realtypes - - @classmethod - def realtype_by_desc_from_datfile( - cls, dat_file: Optional[Union[str, PathLike, BinaryIO]] = None - ) -> Dict[str, KiwoomOpenApiPlusRealType]: - realtypes = cls.realtypes_from_datfile(dat_file) - result = {realtype.desc: realtype for realtype in realtypes} - return result - - @classmethod - def dump_realtype_by_desc( - cls, - dump_file: Optional[Union[str, PathLike, TextIO]] = None, - dat_file: Optional[Union[str, PathLike, BinaryIO]] = None, - encoding: Optional[str] = None, - ): - if dump_file is None: - dump_file = cls.REALTYPE_BY_DESC_DUMP_FILEPATH - if isinstance(dump_file, str): - dump_file = Path(dump_file) - with contextlib.ExitStack() as stack: - if isinstance(dump_file, PathLike): - dump_filename = dump_file - if encoding is None: - encoding = default_encoding - dump_file = open(dump_file, "w", encoding=encoding) - dump_file = stack.enter_context(dump_file) - else: - dump_filename = None - result = cls.realtype_by_desc_from_datfile(dat_file) - for tr_code in result: - result[tr_code] = result[tr_code].to_dict() - if dump_filename is not None: - cls.logger.debug("Saving realtype to %s", dump_filename) - return json.dump( - result, - dump_file, - indent=4, - sort_keys=True, - ensure_ascii=False, - ) - - @classmethod - def realtype_by_desc_from_dump_file( - cls, - dump_file: Optional[Union[str, PathLike, TextIO]] = None, - encoding: Optional[str] = None, - ) -> Dict[str, KiwoomOpenApiPlusRealType]: - if dump_file is None: - dump_file = cls.REALTYPE_BY_DESC_DUMP_FILEPATH - if isinstance(dump_file, str): - dump_file = Path(dump_file) - with contextlib.ExitStack() as stack: - if isinstance(dump_file, PathLike): - if dump_file.exists() and dump_file.stat().st_size > 0: - if encoding is None: - encoding = default_encoding - dump_file = open(dump_file, "r", encoding=encoding) - dump_file = stack.enter_context(dump_file) - else: - return {} - result = json.load(dump_file) - for desc in result: - result[desc] = cls.from_dict(result[desc]) - return result - - @classmethod - def load_from_dump_file( - cls, dump_file: Optional[Union[str, PathLike, TextIO]] = None - ): - cls.REALTYPE_BY_DESC = cls.realtype_by_desc_from_dump_file(dump_file) - cls.Fid.load_from_dump_file() - - @classmethod - def load_from_datfile( - cls, dat_file: Optional[Union[str, PathLike, BinaryIO]] = None - ): - cls.REALTYPE_BY_DESC = cls.realtype_by_desc_from_datfile(dat_file) - cls.Fid.load_from_dump_file() - - @classmethod - def load(cls): - try: - cls.load_from_datfile() - except FileNotFoundError: - cls.load_from_dump_file() - - -KiwoomOpenApiPlusRealType.Fid.__outer_class__ = KiwoomOpenApiPlusRealType -KiwoomOpenApiPlusRealType.load() - - -def main(): - KiwoomOpenApiPlusRealType.dump_realtype_by_desc() - - -if __name__ == "__main__": - main() diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.py deleted file mode 100644 index 3f5faa80..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager.py +++ /dev/null @@ -1,120 +0,0 @@ -import collections -import random -import threading - -from typing import Collection, List, Optional, Union - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions import ( - KiwoomOpenApiPlusDispatchFunctions, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusScreenManager(Logging): - - MAXIMUM_NUMBER_OF_SCREENS = 200 - - def __init__(self, control: Optional[KiwoomOpenApiPlusDispatchFunctions] = None): - self._control = control - self._lock = threading.RLock() - self._occupied_screen_nos = collections.deque( - maxlen=self.MAXIMUM_NUMBER_OF_SCREENS - ) - self._borrow_count_by_screen_no = {} - - @staticmethod - def number_to_screen_no(number: int) -> str: - return str(number).zfill(4) - - @staticmethod - def screen_no_to_number(screen_no: str) -> int: - return int(screen_no) - - def is_inuse(self, screen_no: str) -> bool: - return ( - screen_no is not None - and self.screen_no_to_number(screen_no) in self._occupied_screen_nos - ) - - def get_single_free_screen(self, exclude: Optional[Collection[str]] = None) -> str: - if exclude is None: - exclude = [] - else: - exclude = [self.screen_no_to_number(scrnno) for scrnno in exclude] - exclude = set(exclude) - with self._lock: - if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: - self.logger.warning( - "Requesting free screen, but already using maximum number of screens." - ) - screen_no = random.choice( - [ - i - for i in range(1, 10000) - if i not in self._occupied_screen_nos and i not in exclude - ] - ) - screen_no = self.number_to_screen_no(screen_no) - return screen_no - - def get_multiple_free_screens(self, count: int) -> List[str]: - screens = [] - for _ in range(count): - screens.append(self.get_single_free_screen(exclude=screens)) - return screens - - def get_free_screen(self, count: Optional[int] = None) -> Union[str, List[str]]: - if count is None: - return self.get_single_free_screen() - else: - return self.get_multiple_free_screens(count) - - def borrow_screen( - self, screen_no: Optional[str] = None, reuse: bool = True, pop: bool = True - ) -> str: - with self._lock: - if screen_no is None or screen_no == "": - screen_no = self.get_single_free_screen() - if not reuse: - if self.is_inuse(screen_no): - raise KiwoomOpenApiPlusError( - "Borrowing screen %s, but it's already is use." % screen_no - ) - if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: - self.logger.warning( - "Borrowing a screen, but already using maximum number of screens." - ) - if pop: - oldest = self._occupied_screen_nos.popleft() - del self._borrow_count_by_screen_no[oldest] - self.logger.warning( - "Oldest screen %s popped.", - self.number_to_screen_no(oldest), - ) - else: - raise KiwoomOpenApiPlusError("Cannot allocate more screen") - screen_no_int = self.screen_no_to_number(screen_no) - if not self.is_inuse(screen_no): - self._occupied_screen_nos.append(screen_no_int) - self._borrow_count_by_screen_no[screen_no_int] = ( - self._borrow_count_by_screen_no.get(screen_no_int, 0) + 1 - ) - if len(self._occupied_screen_nos) == self.MAXIMUM_NUMBER_OF_SCREENS: - self.logger.warning("Maximum number of screens reached.") - return screen_no - - def return_screen(self, screen_no: str) -> bool: - try: - with self._lock: - screen_no_int = self.screen_no_to_number(screen_no) - self._borrow_count_by_screen_no[screen_no_int] -= 1 - if self._borrow_count_by_screen_no[screen_no_int] == 0: - self._occupied_screen_nos.remove(screen_no_int) - del self._borrow_count_by_screen_no[screen_no_int] - return True - except (KeyError, ValueError): - self.logger.warning("Returned screen %s, but not found.", screen_no) - return False diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.py deleted file mode 100644 index bf846b44..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import annotations - -import inspect -import threading - -from typing import Any, Callable, Generic, List, Optional, TypeVar - -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import ( - KiwoomOpenApiPlusEventHandlerSignature, -) -from koapy.compat.pyside2 import PYQT5, PYSIDE2, PythonQtError -from koapy.compat.pyside2.QtAxContainer import QAxWidget -from koapy.utils.logging.Logging import Logging - -P = ParamSpec("P") -R = TypeVar("R") - - -class KiwoomOpenApiPlusSignalConnector(Logging, Generic[P, R]): - def __init__(self, name: str): - super().__init__() - - self._name = name - self._lock = threading.RLock() - self._slots: List[Callable[P, R]] = [] - - self._signature = KiwoomOpenApiPlusEventHandlerSignature.from_name(self._name) - self._param_types = [ - (p.annotation) for p in self._signature.parameters.values() - ] - - if PYSIDE2: - self._signal = self._signature.to_pyside2_event_signal() - - self.__name__ = self._name - self.__signature__ = self._signature - - def is_valid_slot(self, slot: Callable[..., Any]) -> bool: - slot_signature = inspect.signature(slot) - slot_types = [(p.annotation) for p in slot_signature.parameters.values()] - condition = len(self._param_types) == len( - slot_types - ) # currently only check parameter length - return condition - - def connect_to(self, control: QAxWidget): - if PYSIDE2: - return control.connect(self._signal, self) - elif PYQT5: - return getattr(control, self._name).connect(self) - else: - raise PythonQtError("Unsupported Qt bindings") - - def disconnect_from(self, control: QAxWidget): - if PYSIDE2: - return control.disconnect(self._signal, self) - elif PYQT5: - return getattr(control, self._name).disconnect(self) - else: - raise PythonQtError("Unsupported Qt bindings") - - def connect(self, slot: Callable[..., Any]): - if not self.is_valid_slot(slot): - raise ValueError("Tried to connect invalid slot: %s" % slot) - with self._lock: - if slot not in self._slots: - self._slots.append(slot) - - def disconnect(self, slot: Optional[Callable[..., Any]] = None): - with self._lock: - if slot is None: - self._slots.clear() - elif slot in self._slots: - self._slots.remove(slot) - else: - self.logger.warning("Tried to disconnect a slot that doesn't exist") - - def call(self, *args: P.args, **kwargs: P.kwargs) -> R: - # make a copy in order to prevent modification during iteration problem - with self._lock: - slots = list(self._slots) - # use Thread with await/join for concurrency? - for slot in slots: - slot(*args, **kwargs) - - def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: - return self.call(*args, **kwargs) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.py deleted file mode 100644 index b7d5644f..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature.py +++ /dev/null @@ -1,84 +0,0 @@ -from inspect import Parameter, Signature -from typing import Dict - -import pythoncom - -from koapy.compat.pyside2 import PYSIDE2 - -if PYSIDE2: - from koapy.compat.pyside2.QtCore import SIGNAL - -try: - from types import NoneType -except ImportError: - NoneType = type(None) - - -class KiwoomOpenApiPlusSignature(Signature): - - PYTHONTYPE_TO_QTTYPE = { - int: "int", - str: "const QString&", - } - - COMTYPE_TO_PYTHONTYPE = { - pythoncom.VT_I4: int, - pythoncom.VT_BSTR: str, - pythoncom.VT_VARIANT: Parameter.empty, - pythoncom.VT_VOID: NoneType, - } - - def __init__( - self, - name: str, - parameters: Dict[str, Parameter] = None, - return_annotation=Signature.empty, - ): - self._name = name - super().__init__(parameters, return_annotation=return_annotation) - - @property - def name(self) -> str: - return self._name - - @classmethod - def _pythontype_to_qttype(cls, typ): - return cls.PYTHONTYPE_TO_QTTYPE[typ] - - def to_pyside2_function_prototype(self) -> str: - name = self._name - parameters = self.parameters - parameters = parameters.values() - parameters = [self._pythontype_to_qttype(p.annotation) for p in parameters] - prototype = "{}({})".format(name, ", ".join(parameters)) - return prototype - - if PYSIDE2: - - def to_pyside2_event_signal(self) -> str: - return SIGNAL(self.to_pyside2_function_prototype()) - - @classmethod - def _comtype_to_pythontype(cls, typ): - return cls.COMTYPE_TO_PYTHONTYPE.get(typ, Parameter.empty) - - @classmethod - def _from_entry(cls, name, entry): - arg_names = entry.names[1:] - arg_types = [typ[0] for typ in entry.desc[2]] - return_type = entry.desc[8][0] - parameters = [ - Parameter( - name=arg_name, - kind=Parameter.POSITIONAL_OR_KEYWORD, - annotation=cls._comtype_to_pythontype(arg_type), - ) - for arg_name, arg_type in zip(arg_names, arg_types) - ] - return_annotation = cls._comtype_to_pythontype(return_type) - signature = cls( - name=name, - parameters=parameters, - return_annotation=return_annotation, - ) - return signature diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.py deleted file mode 100644 index 06ec4166..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo.py +++ /dev/null @@ -1,516 +0,0 @@ -from __future__ import annotations - -import contextlib -import io -import json -import zipfile - -from os import PathLike -from pathlib import Path -from typing import Any, Dict, List, Optional, Sequence, TextIO, Union - -from koapy.config import debug, default_encoding -from koapy.utils.logging.Logging import Logging -from koapy.utils.serialization import JsonSerializable - - -class KiwoomOpenApiPlusTrInfo(JsonSerializable, Logging): - - TRINFO_BY_CODE_DUMP_FILEDIR = Path(__file__).parent.parent / "data/metadata" - TRINFO_BY_CODE_DUMP_FILENAME = "trinfo_by_code.json" - TRINFO_BY_CODE_DUMP_FILEPATH = ( - TRINFO_BY_CODE_DUMP_FILEDIR / TRINFO_BY_CODE_DUMP_FILENAME - ) - - TRINFO_BY_CODE: Dict[str, KiwoomOpenApiPlusTrInfo] = {} - - class Field(JsonSerializable): - def __init__( - self, - name: Optional[str] = None, - start: Optional[int] = None, - offset: Optional[int] = None, - fid: Optional[int] = None, - ): - self.name = name - self.start = start - self.offset = offset - self.fid = fid - - def __repr__(self): - return "{}({!r}, {!r}, {!r}, {!r})".format( - self.__class__.__name__, - self.name, - self.start, - self.offset, - self.fid, - ) - - def __eq__(self, other): - if isinstance(other, type(self)): - return ( - self.name == other.name - and self.start == other.start - and self.offset == other.offset - and self.fid == other.fid - ) - return False - - class OutputsParams(JsonSerializable): - def __init__( - self, - max_repeat_count: Optional[str] = None, - four_if_multi: Optional[str] = None, - repeat_count_desc: Optional[str] = None, - ): - self.max_repeat_count = max_repeat_count - self.four_if_multi = four_if_multi - self.repeat_count_desc = repeat_count_desc - - def __repr__(self): - return "{}({!r}, {!r}, {!r})".format( - self.__class__.__name__, - self.max_repeat_count, - self.four_if_multi, - self.repeat_count_desc, - ) - - def __eq__(self, other): - if isinstance(other, type(self)): - return ( - self.max_repeat_count == other.max_repeat_count - and self.four_if_multi == other.four_if_multi - and self.repeat_count_desc == other.repeat_count_desc - ) - return False - - def __init__( - self, - tr_code: Optional[str] = None, - tr_name: Optional[str] = None, - tr_name_svr: Optional[str] = None, - tr_type: Optional[str] = None, - gfid: Optional[str] = None, - inputs_name: Optional[str] = None, - inputs: Optional[Sequence[Field]] = None, - single_outputs_name: Optional[str] = None, - single_outputs_params: Optional[OutputsParams] = None, - single_outputs: Optional[Sequence[Field]] = None, - multi_outputs_name: Optional[str] = None, - multi_outputs_params: Optional[OutputsParams] = None, - multi_outputs: Optional[Sequence[Field]] = None, - ): - self.tr_code = tr_code - self.tr_name = tr_name - self.tr_name_svr = tr_name_svr - self.tr_type = tr_type - self.gfid = gfid - self.inputs_name = inputs_name - self.inputs = inputs - self.single_outputs_name = single_outputs_name - self.single_outputs_params = single_outputs_params - self.single_outputs = single_outputs - self.multi_outputs_name = multi_outputs_name - self.multi_outputs_params = multi_outputs_params - self.multi_outputs = multi_outputs - - @property - def name(self): - return self.inputs_name - - @property - def code(self): - return self.tr_code - - def __repr__(self): - return "{}({!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r}, {!r})".format( - self.__class__.__name__, - self.tr_code, - self.tr_name, - self.tr_name_svr, - self.tr_type, - self.gfid, - self.inputs_name, - self.inputs, - self.single_outputs_name, - self.single_outputs_params, - self.single_outputs, - self.multi_outputs_name, - self.multi_outputs_params, - self.multi_outputs, - ) - - def __eq__(self, other): - if isinstance(other, type(self)): - return ( - self.tr_code.lower() == other.tr_code.lower() - and self.tr_name == other.tr_name - and self.tr_name_svr == other.tr_name_svr - and self.tr_type == other.tr_type - and self.gfid == other.gfid - and self.inputs_name == other.inputs_name - and self.inputs == other.inputs - and self.single_outputs_name == other.single_outputs_name - and self.single_outputs_params == other.single_outputs_params - and self.single_outputs == other.single_outputs - and self.multi_outputs_name == other.multi_outputs_name - and self.multi_outputs_params == other.multi_outputs_params - and self.multi_outputs == other.multi_outputs - ) - return False - - def to_dict(self) -> Dict[str, Any]: - dic = dict(self.__dict__) - for attr, value in dic.items(): - if isinstance(value, list): - dic[attr] = [ - field.to_dict() if isinstance(field, JsonSerializable) else field - for field in value - ] - elif isinstance(value, JsonSerializable): - dic[attr] = value.to_dict() - return dic - - @classmethod - def from_dict(cls, dic: Dict[str, Any]) -> KiwoomOpenApiPlusTrInfo: - output = cls() - for name in output.__dict__: - value = dic.get(name) - if isinstance(value, list): - fields = [cls.Field.from_dict(d) for d in value] - setattr(output, name, fields) - elif isinstance(value, dict): - outputs_params = cls.OutputsParams(**value) - setattr(output, name, outputs_params) - else: - setattr(output, name, value) - return output - - def get_input_names(self) -> List[str]: - return [input_.name for input_ in self.inputs] - - def get_single_output_names(self) -> List[str]: - return [output.name for output in self.single_outputs] - - def get_multi_output_names(self) -> List[str]: - return [output.name for output in self.multi_outputs] - - @classmethod - def get_trcode_list(cls) -> List[str]: - return list(cls.TRINFO_BY_CODE.keys()) - - @classmethod - def get_trinfo_list(cls) -> List[KiwoomOpenApiPlusTrInfo]: - return list(cls.TRINFO_BY_CODE.values()) - - @classmethod - def get_trinfo_by_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo]: - return cls.TRINFO_BY_CODE.get(trcode.lower()) - - @classmethod - def of(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo]: - return cls.get_trinfo_by_code(trcode) - - @classmethod - def from_code(cls, trcode: str) -> Optional[KiwoomOpenApiPlusTrInfo]: - return cls.get_trinfo_by_code(trcode) - - @classmethod - def from_encfile( - cls, - f: Union[str, PathLike, TextIO], - tr_code: Optional[str] = None, - encoding: Optional[str] = None, - ) -> KiwoomOpenApiPlusTrInfo: - with contextlib.ExitStack() as stack: - if isinstance(f, str): - f = Path(f) - if isinstance(f, PathLike): - filename = f - if encoding is None: - encoding = "euc-kr" - f = open(filename, "r", encoding=encoding) - f = stack.enter_context(f) - tr_code = filename.stem.lower() - elif tr_code is None: - raise ValueError("Argument tr_code should be given.") - - lines = iter(f) - lines = map(lambda line: line.rstrip("\n"), lines) - lines = filter(lambda line: len(line.strip()) > 0, lines) - - line = next(lines) - assert line == "[TRINFO]" - line = next(lines) - assert line.startswith("TRName=") - tr_name = line.split("=", 1)[1] - line = next(lines) - tr_name_svr = "" - if line.startswith("TRNameSVR="): - tr_name_svr = line.split("=", 1)[1] - line = next(lines) - assert line.startswith("TRType=") - tr_type = line.split("=", 1)[1] - line = next(lines) - gfid = "" - if line.startswith("GFID="): - gfid = line.split("=", 1)[1] - line = next(lines) - assert line == "[INPUT]" - line = next(lines) - assert line.startswith("@START_") - inputs_name = line.split("_", 1)[1].split("=", 1)[0] - line = next(lines) - inputs = [] - while not line.startswith("@END_"): - input_name, triple = [ - item.strip() for item in line.strip().split("=", 1) - ] - triple = [item.strip() for item in triple.split(",")] - start, offset, fid = [int(item) for item in triple] - inputs.append(cls.Field(input_name, start, offset, fid)) - line = next(lines) - line = next(lines) - single_outputs_name = "" - single_outputs_params = cls.OutputsParams() - single_outputs = [] - multi_outputs_name = "" - multi_outputs_params = cls.OutputsParams() - multi_outputs = [] - assert line == "[OUTPUT]" - line = next(lines) - assert line.startswith("@START_") - outputs_name, outputs_params = line.split("_", 1)[1].split("=", 1) - outputs_params = outputs_params.split(",") - outputs_params = tuple(outputs_params) - outputs = [] - if outputs_params == ("*", "*", "*"): - single_outputs_name = outputs_name - single_outputs_params = cls.OutputsParams(*outputs_params) - single_outputs = outputs - else: - multi_outputs_name = outputs_name - multi_outputs_params = cls.OutputsParams(*outputs_params) - multi_outputs = outputs - line = next(lines) - while not line.startswith("@END_"): - output_name, triple = [ - item.strip() for item in line.strip().split("=", 1) - ] - triple = [item.strip() for item in triple.split(",")] - start, offset, fid = [int(item) if item else 0 for item in triple] - outputs.append(cls.Field(output_name, start, offset, fid)) - line = next(lines) - try: - line = next(lines) - except StopIteration: - pass - else: - if line.startswith("@START_"): - outputs_name, outputs_params = line.split("_", 1)[1].split("=", 1) - outputs_params = outputs_params.split(",") - outputs_params = tuple(outputs_params) - outputs = [] - if outputs_params == ("*", "*", "*"): - single_outputs_name = outputs_name - single_outputs_params = cls.OutputsParams(*outputs_params) - single_outputs = outputs - else: - multi_outputs_name = outputs_name - multi_outputs_params = cls.OutputsParams(*outputs_params) - multi_outputs = outputs - line = next(lines) - while not line.startswith("@END_"): - output_name, triple = [ - item.strip() for item in line.strip().split("=", 1) - ] - triple = [item.strip() for item in triple.split(",")] - start, offset, fid = [ - int(item) if item else 0 for item in triple - ] - outputs.append(cls.Field(output_name, start, offset, fid)) - line = next(lines) - return cls( - tr_code, - tr_name, - tr_name_svr, - tr_type, - gfid, - inputs_name, - inputs, - single_outputs_name, - single_outputs_params, - single_outputs, - multi_outputs_name, - multi_outputs_params, - multi_outputs, - ) - - @classmethod - def infos_from_data_dir( - cls, - data_dir: Optional[Union[str, PathLike]] = None, - encoding: Optional[str] = None, - module_path: Optional[str] = None, - ) -> List[KiwoomOpenApiPlusTrInfo]: - if data_dir is None: - if module_path is None: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - module_path = API_MODULE_PATH - data_dir = module_path / "data" - - if isinstance(data_dir, str): - data_dir = Path(data_dir) - - if encoding is None: - encoding = "euc-kr" - - if debug: - cls.logger.debug("Reading files under %s", data_dir) - - enc_filenames = [filename.name.lower() for filename in data_dir.iterdir()] - enc_filenames = [ - filename - for filename in enc_filenames - if filename.startswith("o") and filename.endswith(".enc") - ] - results = [] - for filename in enc_filenames: - full_filename = data_dir / filename - with zipfile.ZipFile(full_filename) as z: - for info in z.infolist(): - inner_filename = info.filename - tr_code = Path(inner_filename).stem.lower() - if debug: - cls.logger.debug( - "Reading file %s inside %s", inner_filename, full_filename - ) - with z.open(info) as b: - with io.TextIOWrapper(b, encoding=encoding) as f: - results.append(cls.from_encfile(f, tr_code)) - return results - - @classmethod - def trinfo_by_code_from_data_dir( - cls, data_dir: Optional[Union[str, PathLike]] = None - ) -> Dict[str, KiwoomOpenApiPlusTrInfo]: - infos = cls.infos_from_data_dir(data_dir) - result = {info.tr_code: info for info in infos} - return result - - @classmethod - def dump_trinfo_by_code( - cls, - dump_file: Optional[Union[str, PathLike, TextIO]] = None, - data_dir: Optional[str] = None, - encoding: Optional[str] = None, - ): - if dump_file is None: - dump_file = cls.TRINFO_BY_CODE_DUMP_FILEPATH - with contextlib.ExitStack() as stack: - if isinstance(dump_file, str): - dump_file = Path(dump_file) - if isinstance(dump_file, PathLike): - dump_filename = dump_file - if encoding is None: - encoding = default_encoding - dump_file = open(dump_file, "w", encoding=encoding) - dump_file = stack.enter_context(dump_file) - else: - dump_filename = None - result = cls.trinfo_by_code_from_data_dir(data_dir) - for tr_code in result: - result[tr_code] = result[tr_code].to_dict() - if dump_filename is not None: - cls.logger.debug("Saving trinfo to %s", dump_filename) - return json.dump( - result, - dump_file, - indent=4, - sort_keys=True, - ensure_ascii=False, - ) - - @classmethod - def trinfo_by_code_from_dump_file( - cls, - dump_file: Optional[Union[str, PathLike, TextIO]] = None, - encoding: Optional[str] = None, - ) -> Dict[str, KiwoomOpenApiPlusTrInfo]: - if dump_file is None: - dump_file = cls.TRINFO_BY_CODE_DUMP_FILEPATH - with contextlib.ExitStack() as stack: - if isinstance(dump_file, str): - dump_file = Path(dump_file) - if isinstance(dump_file, PathLike): - if dump_file.exists() and dump_file.stat().st_size > 0: - if encoding is None: - encoding = default_encoding - dump_file = open(dump_file, "r", encoding=encoding) - dump_file = stack.enter_context(dump_file) - else: - return {} - result = json.load(dump_file) - for tr_code in result: - item = cls.from_dict(result[tr_code]) - result[tr_code] = item - return result - - @classmethod - def load_from_dump_file( - cls, dump_file: Optional[Union[str, PathLike, TextIO]] = None - ): - cls.TRINFO_BY_CODE = cls.trinfo_by_code_from_dump_file(dump_file) - - @classmethod - def load_from_data_dir(cls, data_dir: Optional[Union[str, PathLike]] = None): - cls.TRINFO_BY_CODE = cls.trinfo_by_code_from_data_dir(data_dir) - - @classmethod - def load(cls): - try: - cls.load_from_data_dir() - except FileNotFoundError: - cls.load_from_dump_file() - - -KiwoomOpenApiPlusTrInfo.load() - - -def main(): - KiwoomOpenApiPlusTrInfo.dump_trinfo_by_code() - - -def infer_fids_by_tr_outputs(output_filename=None): - if output_filename is None: - output_filename = "fid.xlsx" - infos = KiwoomOpenApiPlusTrInfo.infos_from_data_dir() - fields = [] - for info in infos: - for field in info.single_outputs: - fields.append(field) - for field in info.multi_outputs: - fields.append(field) - pairs = [[field.fid, field.name] for field in fields if field.fid != -1] - import string # pylint: disable=import-outside-toplevel - - for pair in pairs: - if pair[1].startswith("풋_"): - pair[1] = pair[1][2:] - if not pair[1][0] in string.ascii_letters and pair[1][-1] in "ns": - pair[1] = pair[1][:-1] - pair[1] = pair[1].upper() - pairs = [tuple(pair) for pair in pairs] - pairs = list(set(pairs)) - pairs = sorted(pairs, key=lambda item: item[0]) - import pandas as pd # pylint: disable=import-outside-toplevel - - df = pd.DataFrame.from_records(pairs) - df.to_excel(output_filename, header=False, index=False) - - -if __name__ == "__main__": - main() diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.py deleted file mode 100644 index 2a2db6b3..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib.py +++ /dev/null @@ -1,13 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - DISPATCH_CLSID, - EVENT_CLSID, - TYPELIB_SPEC, -) -from koapy.utils.pywin32 import BuildOleItems, LoadTypeLib - -TYPELIB = LoadTypeLib(TYPELIB_SPEC) - -OLE_ITEMS, ENUM_ITEMS, RECORD_ITEMS, VTABLE_ITEMS = BuildOleItems(TYPELIB_SPEC, TYPELIB) - -DISPATCH_OLE_ITEM = OLE_ITEMS.get(DISPATCH_CLSID) -EVENT_OLE_ITEM = OLE_ITEMS.get(EVENT_CLSID) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.py deleted file mode 100644 index 676a43f5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path - -from pywintypes import IID - -from koapy.utils.pywin32 import GetLatestTypelibSpec, GetTypelibSpecs - -CONTROL_PROGID = "KHOPENAPI.KHOpenApiCtrl.1" - -CONTROL_CLSID = IID("{A1574A0D-6BFA-4BD7-9020-DED88711818D}") -DISPATCH_CLSID = IID("{CF20FBB6-EDD4-4BE5-A473-FEF91977DEB6}") -EVENT_CLSID = IID("{7335F12D-8973-4BD5-B7F0-12DF03D175B7}") -MODULE_CLSID = IID("{6D8C2B4D-EF41-4750-8AD4-C299033833FB}") - -TYPELIB_SPECS = GetTypelibSpecs(MODULE_CLSID) -TYPELIB_SPEC = GetLatestTypelibSpec(TYPELIB_SPECS) - -TYPELIB_DLL_PATH = TYPELIB_SPEC and TYPELIB_SPEC.dll and Path(TYPELIB_SPEC.dll) - -API_MODULE_PATH_FROM_DEFAULT_INSTALLATION = Path("C:\\OpenAPI") -API_MODULE_PATH_FROM_TYPELIB_DLL = TYPELIB_DLL_PATH and TYPELIB_DLL_PATH.parent -API_MODULE_PATH = ( - API_MODULE_PATH_FROM_TYPELIB_DLL or API_MODULE_PATH_FROM_DEFAULT_INSTALLATION -) diff --git a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.py b/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.py deleted file mode 100644 index 9a58be82..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater.py +++ /dev/null @@ -1,225 +0,0 @@ -import os -import subprocess -import sys - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetMixin, -) -from koapy.utils.ctypes import is_admin -from koapy.utils.logging.Logging import Logging -from koapy.utils.platform import is_32bit -from koapy.utils.subprocess import Popen, function_to_subprocess_args - - -class KiwoomOpenApiPlusVersionUpdater(Logging): - def __init__(self, credentials): - self._credentials = credentials - - def get_api_module_path(self): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - module_path = API_MODULE_PATH - return module_path - - def get_autologin_dat(self): - module_path = self.get_api_module_path() - autologin_dat = module_path / "system" / "Autologin.dat" - return autologin_dat - - def is_autologin_enabled(self): - autologin_dat = self.get_autologin_dat() - return autologin_dat.exists() - - def disable_autologin(self): - self.logger.info("Disabling auto login") - autologin_dat = self.get_autologin_dat() - if autologin_dat.exists(): - self.logger.info("Removing %s", autologin_dat) - os.remove(autologin_dat) - self.logger.info("Disabled auto login") - return True - else: - self.logger.info("Autologin is already disabled") - return False - - @classmethod - def open_login_window_impl(cls): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( - KiwoomOpenApiPlusQAxWidget, - ) - from koapy.compat.pyside2.QtWidgets import QApplication - - cls.logger.info("Opening login window") - app = QApplication(sys.argv) - control = KiwoomOpenApiPlusQAxWidget() - if control.GetConnectState() == 0: - - def OnEventConnect(errcode): - control.OnEventConnect.disconnect(OnEventConnect) - KiwoomOpenApiPlusError.try_or_raise(errcode) - app.exit(errcode) - - control.OnEventConnect.connect(OnEventConnect) - KiwoomOpenApiPlusError.try_or_raise(control.CommConnect()) - return app.exec_() - - def open_login_window(self): - # opening login window is a blocking process. (`app.exec_()` is the blocking process and will wait for `app.exit()`) - # also it's hard to use both PySide2/PyQt5 and pywinauto at the same time in the same process due to compatibility issue. - # - # in order to avoid the issues mentioned above we are creating login window in a separate process. - # and then will do login using pywinauto in another process using `login_using_pywinauto()` function. - # - # this process will stay alive until `OnEventConnect` event happens, hopefully a successful login. - # - # for more information about the compatibility issue between PySide2/PyQt5 and pywinauto, check the following link: - # https://github.com/pywinauto/pywinauto/issues/472 - - def main(): - # pylint: disable=redefined-outer-name,import-self - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( - KiwoomOpenApiPlusVersionUpdater, - ) - - KiwoomOpenApiPlusVersionUpdater.open_login_window_impl() - - cmd = function_to_subprocess_args(main) - creationflags = subprocess.CREATE_NEW_PROCESS_GROUP - proc = Popen(cmd, creationflags=creationflags) - return proc - - @classmethod - def show_account_window_impl(cls): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( - KiwoomOpenApiPlusQAxWidget, - ) - from koapy.compat.pyside2.QtWidgets import QApplication - - cls.logger.info("Showing account window") - app = QApplication(sys.argv) - control = KiwoomOpenApiPlusQAxWidget() - if control.GetConnectState() == 0: - - def OnEventConnect(errcode): - control.OnEventConnect.disconnect(OnEventConnect) - KiwoomOpenApiPlusError.try_or_raise(errcode) - control.KOA_Functions("ShowAccountWindow", "") - app.exit(errcode) - - control.OnEventConnect.connect(OnEventConnect) - KiwoomOpenApiPlusError.try_or_raise(control.CommConnect()) - return app.exec_() - - def show_account_window(self): - # this function does pretty much the same job like the `open_login_window()` function. - # but the difference is that it will show up the account setting window after successful login, - # so that we can (re-)enable the auto login functionality provided by the OpenAPI itself. - # - # this process will stay live until the account window is closed in the `OnEventConnect` event, - # hopefully after successfully enabling the auto login functionality. - # - # note that the `control.KOA_Functions('ShowAccountWindow', '')` line is also blocking process. - # so it will block until the account window is closed after enabling the auto login. - - def main(): - # pylint: disable=redefined-outer-name,import-self - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( - KiwoomOpenApiPlusVersionUpdater, - ) - - KiwoomOpenApiPlusVersionUpdater.show_account_window_impl() - - cmd = function_to_subprocess_args(main) - creationflags = subprocess.CREATE_NEW_PROCESS_GROUP - proc = Popen(cmd, creationflags=creationflags) - return proc - - @classmethod - def check_apply_simulation_window(cls): - import pywinauto - - desktop = pywinauto.Desktop(allow_magic_lookup=False) - apply_simulation_window = desktop.window(title="모의투자 참가신청") - - try: - timeout_apply_simulation = 5 - apply_simulation_window.wait("ready", timeout_apply_simulation) - except pywinauto.timings.TimeoutError: - pass - else: - cls.logger.warning("Please apply for simulation server before using it") - raise RuntimeError("Please apply for simulation server before using it") - - @classmethod - def login_using_pywinauto(cls, credentials): - # reusing the implementation in the mixin - KiwoomOpenApiPlusQAxWidgetMixin.LoginUsingPywinauto_Impl(credentials) - cls.check_apply_simulation_window() - - @classmethod - def enable_autologin_using_pywinauto(cls, credentials): - # reusing the implementation in the mixin - account_passwords = credentials.get("account_passwords") - KiwoomOpenApiPlusQAxWidgetMixin.EnableAutoLoginUsingPywinauto_Impl( - account_passwords - ) - - def enable_autologin(self): - self.logger.info("Start enabling auto login") - - # pylint: disable=unused-variable - account_window_proc = self.show_account_window() - - credentials = self._credentials - - self.login_using_pywinauto(credentials) - self.enable_autologin_using_pywinauto(credentials) - - @classmethod - def handle_version_upgrade_using_pywinauto(cls, pid): - return KiwoomOpenApiPlusQAxWidgetMixin.HandleVersionUpgradeUsingPywinauto_Impl( - pid - ) - - def try_version_update_using_pywinauto(self): - self.logger.info("Trying version update") - - is_autologin_enabled = self.is_autologin_enabled() - - if is_autologin_enabled: - self.disable_autologin() - - login_window_proc = self.open_login_window() - - credentials = self._credentials - - self.login_using_pywinauto(credentials) - - is_updated = self.handle_version_upgrade_using_pywinauto(login_window_proc.pid) - - if is_autologin_enabled: - self.logger.info("Enabling auto login back") - self.enable_autologin() - if is_updated: - self.logger.info("Done update, enabled auto login") - else: - self.logger.info("There was no version update, enabled auto login") - - return is_updated - - def update_version_if_necessary(self): - assert ( - is_32bit() - ), "Automatic version update requires to be run in 32bit environment" - assert ( - is_admin() - ), "Automatic version update requires to be run as administrator" - return self.try_version_update_using_pywinauto() diff --git a/koapy/backend/kiwoom_open_api_plus/core/__init__.py b/koapy/backend/kiwoom_open_api_plus/core/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/core/tools/__init__.py b/koapy/backend/kiwoom_open_api_plus/core/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.py b/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.py deleted file mode 100644 index b6d33c01..00000000 --- a/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs.py +++ /dev/null @@ -1,121 +0,0 @@ -import ast - -from pathlib import Path - -import pythoncom - -from koapy.config import default_encoding - -try: - from ast import unparse -except ImportError: - from astunparse import unparse - - -def generate_python_stubs( - dispatch_class_name=None, - dispatch_file_path=None, - event_class_name=None, - event_file_path=None, - encoding=None, - force_overwrite=False, -): - if dispatch_class_name is None: - dispatch_class_name = "KiwoomOpenApiPlusDispatchFunctionsGenerated" - if dispatch_file_path is None: - dispatch_file_path = dispatch_class_name + ".py" - - if event_class_name is None: - event_class_name = "KiwoomOpenApiPlusEventFunctionsGenerated" - if event_file_path is None: - event_file_path = event_class_name + ".py" - - if encoding is None: - encoding = default_encoding - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib import ( - DISPATCH_OLE_ITEM, - EVENT_OLE_ITEM, - ) - - dispatch_item = DISPATCH_OLE_ITEM - event_item = EVENT_OLE_ITEM - - ellipsis_function_body = [ast.Expr(ast.Constant(Ellipsis))] - comtype_to_annotation = { - pythoncom.VT_I4: int.__name__, - pythoncom.VT_BSTR: str.__name__, - pythoncom.VT_VARIANT: str(None), - pythoncom.VT_VOID: str(None), - } - - dispatch_func_defs = [] - for _name, entry in dispatch_item.mapFuncs.items(): - func_name = entry.names[0] - arg_names = entry.names[1:] - arg_descs = entry.desc.args - args = [ast.arg("self", None)] - for arg_name, (arg_type, _arg_flag, _arg_default, _arg_crap) in zip( - arg_names, arg_descs - ): - arg_type = comtype_to_annotation[arg_type] - arg_annotation = ast.Name(arg_type, ast.Load()) - arg = ast.arg(arg_name, arg_annotation) - arg.lineno = None - arg.col_offset = None - args.append(arg) - args = ast.arguments([], args, None, [], [], None, []) - return_type = entry.desc.rettype[0] - return_type = comtype_to_annotation[return_type] - returns = ast.Name(return_type, ast.Load()) - func_def = ast.FunctionDef(func_name, args, ellipsis_function_body, [], returns) - func_def.lineno = None - func_def.col_offset = None - dispatch_func_defs.append(func_def) - dispatch_class_def = ast.ClassDef( - dispatch_class_name, [], [], dispatch_func_defs, [] - ) - - event_func_defs = [] - for _name, entry in event_item.mapFuncs.items(): - func_name = entry.names[0] - arg_names = entry.names[1:] - arg_descs = entry.desc.args - args = [ast.arg("self", None)] - for arg_name, (arg_type, _arg_flag, _arg_default, _arg_crap) in zip( - arg_names, arg_descs - ): - arg_type = comtype_to_annotation[arg_type] - arg_annotation = ast.Name(arg_type, ast.Load()) - arg = ast.arg(arg_name, arg_annotation) - arg.lineno = None - arg.col_offset = None - args.append(arg) - args = ast.arguments([], args, None, [], [], None, []) - return_type = entry.desc.rettype[0] - return_type = comtype_to_annotation[return_type] - returns = ast.Name(return_type, ast.Load()) - func_def = ast.FunctionDef(func_name, args, ellipsis_function_body, [], returns) - func_def.lineno = None - func_def.col_offset = None - event_func_defs.append(func_def) - - event_class_def = ast.ClassDef(event_class_name, [], [], event_func_defs, []) - - dispatch_file_path = Path(dispatch_file_path) - if not dispatch_file_path.exists() or force_overwrite: - with open(dispatch_file_path, "w", encoding=encoding) as f: - mod = ast.Module([dispatch_class_def], []) - code = unparse(mod) - f.write(code) - - event_file_path = Path(event_file_path) - if not event_file_path.exists() or force_overwrite: - with open(event_file_path, "w", encoding=encoding) as f: - mod = ast.Module([event_class_def], []) - code = unparse(mod) - f.write(code) - - -if __name__ == "__main__": - generate_python_stubs() diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/external/github.png b/koapy/backend/kiwoom_open_api_plus/data/icon/external/github.png deleted file mode 100644 index 8b25551a..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/external/github.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/external/readthedocs.png b/koapy/backend/kiwoom_open_api_plus/data/icon/external/readthedocs.png deleted file mode 100644 index 80687c52..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/external/readthedocs.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-192x192.png deleted file mode 100644 index 268f9e76..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-512x512.png deleted file mode 100644 index ff6fa952..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/apple-touch-icon.png deleted file mode 100644 index 02b442c7..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-16x16.png deleted file mode 100644 index da95cedc..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-32x32.png deleted file mode 100644 index 00f21e37..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon.ico deleted file mode 100644 index 40f037be..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/active/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-192x192.png deleted file mode 100644 index 9f9bca63..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-512x512.png deleted file mode 100644 index eec9c983..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/apple-touch-icon.png deleted file mode 100644 index 2166434b..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-16x16.png deleted file mode 100644 index a0554027..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-32x32.png deleted file mode 100644 index a6dac75e..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon.ico deleted file mode 100644 index 4332a627..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/disabled/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-192x192.png deleted file mode 100644 index dfec3ca0..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-512x512.png deleted file mode 100644 index 777e4ba4..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/apple-touch-icon.png deleted file mode 100644 index 7e850d82..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-16x16.png deleted file mode 100644 index c5fe0016..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-32x32.png deleted file mode 100644 index 4e7586ec..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon.ico deleted file mode 100644 index e8e31a7b..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/manager/normal/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-192x192.png deleted file mode 100644 index cc3ec134..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-512x512.png deleted file mode 100644 index b052c992..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/apple-touch-icon.png deleted file mode 100644 index 5f20e4fa..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-16x16.png deleted file mode 100644 index 7856c097..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-32x32.png deleted file mode 100644 index 6b0aecdd..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon.ico deleted file mode 100644 index 160c2be4..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/active/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-192x192.png deleted file mode 100644 index 691215c4..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-512x512.png deleted file mode 100644 index 83e7af46..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/apple-touch-icon.png deleted file mode 100644 index a55d1c4e..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-16x16.png deleted file mode 100644 index 50ab0c67..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-32x32.png deleted file mode 100644 index 694cd1d5..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon.ico deleted file mode 100644 index 30e3ef88..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/disabled/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/about.txt b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/about.txt deleted file mode 100644 index 5c9e10c5..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/about.txt +++ /dev/null @@ -1,6 +0,0 @@ -This favicon was generated using the following font: - -- Font Title: Leckerli One -- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" -- Font Source: http://fonts.gstatic.com/s/leckerlione/v11/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf -- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL) diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-192x192.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-192x192.png deleted file mode 100644 index 873e684f..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-192x192.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-512x512.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-512x512.png deleted file mode 100644 index 7215fd87..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/android-chrome-512x512.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/apple-touch-icon.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/apple-touch-icon.png deleted file mode 100644 index 220b3973..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/apple-touch-icon.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-16x16.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-16x16.png deleted file mode 100644 index 5f55aa26..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-16x16.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-32x32.png b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-32x32.png deleted file mode 100644 index 847ff0e5..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon-32x32.png and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon.ico b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon.ico deleted file mode 100644 index 251cc8b2..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/favicon.ico and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/site.webmanifest b/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/site.webmanifest deleted file mode 100644 index 45dc8a20..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/icon/server/normal/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.csv b/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.csv deleted file mode 100644 index 8f006d5d..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.csv +++ /dev/null @@ -1,796 +0,0 @@ -fid,name -0,대칭구분 -10,현재가 -11,전일대비 -12,등락율 -13,누적거래량 -14,누적거래대금 -15,거래량 -16,시가 -17,고가 -18,저가 -19,종가 -20,체결시간 -21,호가시간 -22,체결일자 -23,예상체결가 -24,예상체결량 -25,전일대비기호 -26,거래량전일대비 -27,매도호가 -28,매수호가 -29,거래대금증감 -30,전일거래량대비율 -31,거래회전율 -32,거래비용 -36,NAV -37,NAV전일대비 -38,NAV등락율 -39,추적오차율 -40,괴리율 -41,매도호가1 -42,매도호가2 -43,매도호가3 -44,매도호가4 -45,매도호가5 -46,매도호가6 -47,매도호가7 -48,매도호가8 -49,매도호가9 -50,매도호가10 -51,매수호가1 -52,매수호가2 -53,매수호가3 -54,매수호가4 -55,매수호가5 -56,매수호가6 -57,매수호가7 -58,매수호가8 -59,매수호가9 -60,매수호가10 -61,매도수량1 -62,매도수량2 -63,매도수량3 -64,매도수량4 -65,매도수량5 -66,매도수량6 -67,매도수량7 -68,매도수량8 -69,매도수량9 -70,매도수량10 -71,매수수량1 -72,매수수량2 -73,매수수량3 -74,매수수량4 -75,매수수량5 -76,매수수량6 -77,매수수량7 -78,매수수량8 -79,매수수량9 -80,매수수량10 -81,매도호가직전대비1 -82,매도호가직전대비2 -83,매도호가직전대비3 -84,매도호가직전대비4 -85,매도호가직전대비5 -86,매도호가직전대비6 -87,매도호가직전대비7 -88,매도호가직전대비8 -89,매도호가직전대비9 -90,매도호가직전대비10 -91,매수호가직전대비1 -92,매수호가직전대비2 -93,매수호가직전대비3 -94,매수호가직전대비4 -95,매수호가직전대비5 -96,매수호가직전대비6 -97,매수호가직전대비7 -98,매수호가직전대비8 -99,매수호가직전대비9 -100,매수호가직전대비10 -101,매도호가건수1 -102,매도호가건수2 -103,매도호가건수3 -104,매도호가건수4 -105,매도호가건수5 -111,매수호가건수1 -112,매수호가건수2 -113,매수호가건수3 -114,매수호가건수4 -115,매수호가건수5 -121,매도호가총잔량 -122,매도호가총잔량직전대비 -123,매도호가총건수 -125,매수호가총잔량 -126,매수호가총잔량직전대비 -127,매수호가총건수 -128,순매수잔량 -129,매수비율 -131,시간외매도호가총잔량 -132,시간외매도호가총잔량직전대비 -135,시간외매수호가총잔량 -136,시간외매수호가총잔량직전대비 -137,호가순잔량 -138,순매도잔량 -139,매도비율 -141,매도거래원1 -142,매도거래원2 -143,매도거래원3 -144,매도거래원4 -145,매도거래원5 -146,매도거래원코드1 -147,매도거래원코드2 -148,매도거래원코드3 -149,매도거래원코드4 -150,매도거래원코드5 -151,매수거래원1 -152,매수거래원2 -153,매수거래원3 -154,매수거래원4 -155,매수거래원5 -156,매수거래원코드1 -157,매수거래원코드2 -158,매수거래원코드3 -159,매수거래원코드4 -160,매수거래원코드5 -161,매도거래원수량1 -162,매도거래원수량2 -163,매도거래원수량3 -164,매도거래원수량4 -165,매도거래원수량5 -166,매도거래원별증감1 -167,매도거래원별증감2 -168,매도거래원별증감3 -169,매도거래원별증감4 -170,매도거래원별증감5 -171,매수거래원수량1 -172,매수거래원수량2 -173,매수거래원수량3 -174,매수거래원수량4 -175,매수거래원수량5 -176,매수거래원별증감1 -177,매수거래원별증감2 -178,매수거래원별증감3 -179,매수거래원별증감4 -180,매수거래원별증감5 -181,미결제약정전일대비 -182,이론가 -183,시장베이시스 -184,이론베이시스 -185,괴리도 -186,괴리율 -187,내재가치 -188,시간가치 -189,내재변동성 -190,델타 -191,감마 -192,베가 -193,세타 -194,로 -195,미결제약정 -196,미결제증감 -197,KOSPI200 -200,예상체결가전일종가대비 -201,예상체결가전일종가대비등락율 -202,매도수량 -203,매도수량증감 -204,매도금액 -205,매도금액증감 -206,매수수량 -207,매수수량증감 -208,매수금액 -209,매수금액증감 -210,순매수수량 -211,순매수수량증감 -212,순매수금액 -213,순매수금액증감 -215,장운영구분 -216,투자자별티커 -217,이점시전순매수수량 -218,순매수증감 -220,체결수익률 -221,ETF수익률 -228,체결강도 -238,예상체결가전일종가대비기호 -240,대표내재변동성 -241,콜내재변동성 -242,풋내재변동성 -243,선물대표내재변동성 -244,선물콜내재변동성 -245,선물풋내재변동성 -246,시초미결제약정수량 -247,최고미결제약정수량 -248,최저미결제약정수량 -251,상한 -252,상승 -253,보합 -254,하한 -255,하락 -256,거래형성종목수 -257,거래형성비율 -260,구분 -261,외국계매도추정합 -262,외국계매도추정합변동 -263,외국계매수추정합 -264,외국계매수추정합변동 -265,NAV/지수괴리율 -266,NAV/ETF괴리율 -267,외국계순매수추정합 -268,외국계순매수변동 -269,전일미결제약정 -271,매도거래원색깔1 -272,매도거래원색깔2 -273,매도거래원색깔3 -274,매도거래원색깔4 -275,매도거래원색깔5 -281,매수거래원색깔1 -282,매수거래원색깔2 -283,매수거래원색깔3 -284,매수거래원색깔4 -285,매수거래원색깔5 -290,장구분 -291,예상체결가 -292,예상체결량 -293,예상체결가전일대비기호 -294,예상체결가전일대비기호 -295,예상체결가전일대비등락율 -299,전일거래량대비예상체결률 -300,종목분류 -301,종목표준코드 -302,종목명 -304,전일거래량 -305,상한가 -306,하한가 -307,기준가 -308,대용가 -309,자본금 -310,액면가 -311,시가총액 -312,상장주식수 -313,보유주식수 -314,한도소진율 -315,결산월 -316,PER -317,대업종구분 -318,소업종구분 -320,CB상한가 -321,CB하한가 -322,최종거래일 -323,잔존일수 -324,행사가 -325,지수환산 -326,신용잔고율 -327,역사적변동성 -329,신용잔고율 -333,횟수 -334,거래원명 -336,시가총액비중 -338,표면이자 -339,피봇 -340,1차저항 -341,2차저항 -342,1차저지 -343,2차저지 -344,취득가능주식수 -345,외국인한도 -346,기준가 -352,테마명 -353,기간수익률 -355,D-1 -356,D-2 -357,D-3 -358,합계 -359,기준한도소진율 -360,소진율증가 -361,배당액지수 -370,종목정보 -371,행사일 -372,만기일 -375,대상지수대비율 -379,콜풋RATIO -389,종목코드 -391,기준가대비시가등락율 -392,기준가대비고가등락율 -393,기준가대비저가등락율 -395,자산코드 -396,전일거래대금 -397,연누적거래대금 -399,외국인한도증감 -401,순위 -402,역사적변동성 -403,영업일기준잔존일 -404,차근달력기준잔존일 -405,차근영업일기준잔존일 -406,차차근달력기준잔존일 -407,차차근영업일기준잔존일 -408,차차차근달력기준잔존일 -409,차차차근영업일기준잔존일 -410,전일순위 -412,스프레드 -413,발행기관 -414,기초자산1 -415,기초자산2 -416,기초자산3 -417,기초자산4 -418,기초자산5 -419,기초자산구성비율1 -420,기초자산구성비율2 -421,기초자산구성비율3 -422,기초자산구성비율4 -423,기초자산구성비율5 -425,행사가격 -426,권리유형 -427,권리행사방식 -428,ELW권리내용 -429,결제방법 -430,최종거래일 -431,전환비율 -432,가격상승참여율 -433,보상율 -434,지급일 -435,지급대리인 -436,ELW만기평가가격 -437,투자지표산출여부 -438,ELW LP주문가능 -439,상장일 -440,발행사명 -441,회차 -442,기초자산명 -443,권리구분 -444,LP보유수량 -445,잔존일수 -446,LP보유비율 -447,LP최종공급일 -448,확정지급금액 -470,대차거래상환주수 -471,잔고주수 -472,잔고금액 -473,대차거래상환주수 -474,잔고주수 -475,잔고금액 -476,대차거래증감 -477,대차거래증감 -500,차익위탁매도수량 -502,차익거래매도수량 -503,차익위탁매도금액 -504,차익매도자기금액 -505,차익매도금액 -508,차익매도비율 -509,차익위탁매수수량 -511,차익거래매수수량 -512,차익매수위탁금액 -513,차익매수자기금액 -514,차익매수금액 -517,차익매수비율 -518,차익위탁순매수금액 -520,차익위탁순매수수량 -522,차익순매수금액 -523,차익순매수수량 -524,비차익위탁매도수량 -526,비차익거래매도수량 -527,비차익위탁매도금액 -529,비차익거래매도금액 -532,비차익매도비율 -533,비차익위탁매수수량 -535,비차익거래매수수량 -536,비차익위탁매수금액 -538,비차익거래매수금액 -541,비차익매수비율 -542,비차익위탁순매수금액 -544,비차익위탁순매수수량 -546,비차익거래순매수금액 -547,비차익거래순매수수량 -548,비차익거래누적 -552,매도차익거래증감액 -553,매수차익거래증감액 -554,공매도량 -555,공매도거래대금 -556,매매비중 -594,통화단위 -621,LP매도1호가잔량 -622,LP매도2호가잔량 -623,LP매도3호가잔량 -624,LP매도4호가잔량 -625,LP매도5호가잔량 -626,LP매도6호가잔량 -627,LP매도7호가잔량 -628,LP매도8호가잔량 -629,LP매도9호가잔량 -630,LP매도10호가잔량 -631,LP매수1호가잔량 -632,LP매수2호가잔량 -633,LP매수3호가잔량 -634,LP매수4호가잔량 -635,LP매수5호가잔량 -636,LP매수6호가잔량 -637,LP매수7호가잔량 -638,LP매수8호가잔량 -639,LP매수9호가잔량 -640,LP매수10호가잔량 -661,LP회원사명1 -662,LP회원사명2 -664,LP회원사명3 -666,패리티 -667,기어링비율 -668,손익분기율 -669,자본지지점 -670,이론가 -671,내재변동성 -672,델타 -673,감마 -674,쎄타 -675,베가 -676,로 -682,레버리지 -683,변동수량 -686,괴리율 -687,예상권리가 -689,조기종료여부 -690,KO베리어 -691,KO접근도 -692,평가시작일자 -693,평가시작시간 -694,평가종료일자 -695,평가종료시간 -696,평가가격 -697,평가완료여부 -698,전체최고가 -699,전체최저가 -704,XRAY순간체결량정리매매구분 -706,XRAY순간체결량증거금100%구분 -709,IV -710,직후최고가 -711,직후최저가 -712,후반장최고가 -713,후반장최저가 -736,이전순매수금액 -764,전체당일 -765,전체누적 -768,추적지수 -769,추적지수전일대비 -770,추적지수전일대비기호 -796,액면가단위 -870,상환 -871,잔고 -872,금액 -873,대비 -874,공여율 -875,잔고율 -876,신규 -900,주문수량 -901,주문가격 -902,미체결수량 -903,체결누계금액 -904,원주문번호 -905,주문구분 -906,매매구분 -907,매도수구분 -908,주문/체결시간 -909,체결번호 -910,체결가 -911,체결량 -912,업무구분 -913,주문상태 -914,단위체결가 -915,단위체결량 -916,대출일 -917,신용구분 -918,만기일 -919,거부사유 -920,화면번호 -928,프로그램순매수금액증감 -929,프로그램순매수수량증감 -930,보유수량 -931,매입단가 -932,총매입가 -933,주문가능수량 -934,당일매도수량 -935,당일매도금액 -936,당일매수수량 -937,당일매수금액 -938,당일매매수수료 -939,당일매매세금 -940,당일HTS매도수수료 -941,당일HTS매수수수료 -942,D+2매수정산금 -944,당일실현손익 -945,당일순매수량 -946,매도/매수구분 -950,당일총매도손익 -951,예수금 -952,사용가능현금 -953,사용가능대용 -954,전일재사용 -955,당일재사용 -956,담보현금 -957,신용금액 -958,신용이자 -959,담보대출수량 -961,현물주문체결이상유무 -962,현물잔고이상유무 -963,현물예수금이상유무 -966,선물주문체결이상유무 -967,선물잔고이상유무 -971,D+1추정예수금 -972,D+2추정예수금 -973,D+1매수/매도정산금 -974,D+2매수/매도정산금 -975,D+1연체변제소요금 -976,D+2연체변제소요금 -977,D+1추정인출가능금 -978,D+2추정인출가능금 -979,현금증거금 -980,대용잔고 -981,대용증거금 -982,수표금액 -983,현금미수금 -984,신용설정보증금 -985,인출가능금액 -990,당일실현손익_유가 -991,당일실현손익률_유가 -992,당일실현손익_신용 -993,당일실현손익률_신용 -1000,52주최고가 -1001,52주최고가일 -1002,52주최고가대비율 -1003,52주최저가 -1004,52주최저가일 -1005,52주최저가대비율 -1006,연중최고 -1009,연중최저 -1018,상장중최고가 -1019,상장중최고가일 -1020,상장중최고가대비율 -1021,상장중최저가 -1022,상장중최저가일 -1023,상장중최저가대비율 -1025,고가 -1026,저가 -1027,기준가 -1028,기준대비 -1029,비중 -1033,이전거래량 -1034,기준률 -1035,현재비율 -1036,급증량 -1037,급증률 -1040,시가대비 -1041,대차거래체결주수합 -1042,대차거래상환주수합 -1043,잔고주수합 -1044,잔고금액합 -1045,대차거래체결주수비율 -1046,대차거래상환주수비율 -1047,잔고주수비율 -1048,잔고금액비율 -1049,매물비 -1051,종목수 -1052,상승종목수 -1054,하락종목수 -1055,전일대비 -1056,등락률 -1058,매도수량 -1059,매수수량 -1060,누적순매수수량 -1063,거래비중 -1065,상장종목수 -1066,외인비중 -1067,전일대비기호 -1077,전체거래비율 -1079,주요종목 -1080,구간구분 -1085,과표기준 -1086,전일배당금 -1087,환산가격 -1088,배수 -1089,원주가격 -1093,ETF대상지수코드 -1094,ETF대상지수명 -1101,금융투자 -1102,보험 -1103,투신 -1104,은행 -1105,기타금융 -1106,연기금등 -1107,기타법인 -1108,개인 -1109,외국인 -1111,주가등락 -1112,등락율 -1113,거래량 -1114,매도상위이탈원 -1115,매도이탈시간 -1116,매수상위이탈원 -1117,매수이탈시간 -1118,조회일자 -1119,조회시간 -1120,비중 -1121,차익매도위탁선물금액 -1122,차익매도자기선물금액 -1123,차익매수위탁선물금액 -1124,차익매수자기선물금액 -1125,차익매도위탁CALL금액 -1126,차익매도자기CALL금액 -1127,차익매수위탁CALL금액 -1128,차익매수자기CALL금액 -1129,차익매도위탁PUT금액 -1130,차익매도자기PUT금액 -1131,차익매수위탁PUT금액 -1132,차익매수자기PUT금액 -1134,기관순매매수량 -1135,기관순매매금액 -1136,기관순매수수량 -1137,외인순매수수량 -1138,외국계 -1139,프로그램 -1140,순매매수량 -1141,순매매금액 -1142,추정평균가 -1143,평균가대비 -1144,대비율 -1145,기간거래량 -1146,한도소진율 -1148,외인순매매평균가 -1179,차익매도선물금액 -1180,차익매수선물금액 -1181,차익매도CALL금액 -1182,차익매수CALL금액 -1183,차익매도PUT금액 -1184,차익매수PUT금액 -1188,외국계 -1189,프로그램 -1201,역사적변동성1 -1202,역사적변동성2 -1203,역사적변동성3 -1204,선물역사적변동성1 -1205,선물역사적변동성2 -1206,선물역사적변동성3 -1215,기관추정평균가 -1217,외인추정평균가 -1221,발동가격 -1223,매매체결처리시각 -1224,VI해제시각 -1225,VI적용구분 -1236,정적기준가격 -1237,동적기준가격 -1238,정적괴리율 -1239,동적괴리율 -1341,원주가격 -1342,ETF과세유형 -1344,업종명 -1369,체결강도5분 -1370,체결강도20분 -1371,체결강도60분 -1396,ETN과세유형 -1400,장중거래량 -1401,장후거래량 -1402,장전거래량 -1404,장중거래대금 -1405,장후거래대금 -1406,장전거래대금 -1408,장중거래비중 -1409,장후거래비중 -1410,장전거래비중 -1411,장중거래대금비중 -1412,장후거래대금비중 -1413,장전거래대금비중 -1414,외인순매매수량 -1415,외인순매매금액 -1489,시가대비등락률 -1490,VI발동횟수 -1600,PER -1601,PBR -1604,EPS -1605,BPS -1608,EV -1610,매출액 -1611,영업이익 -1614,당기순이익 -1630,ROE -1683,유통주식 -1684,유통비율 -1805,금융투자 -1811,보험 -1817,투신 -1823,사모펀드 -1829,은행 -1835,기타금융 -1841,연기금등 -1847,국가 -1853,기타법인 -1859,개인투자자 -1965,외국인투자자 -1971,내외국인 -1977,기관계 -3501,마지막틱갯수 -3502,수정주가구분 -3503,수정비율 -6001,금융투자 -6002,보험 -6003,투신 -6004,은행 -6005,기타금융 -6006,연기금등 -6007,기타법인 -6008,개인투자자 -6009,외국인투자자 -6010,내외국인 -6012,국가 -6013,사모펀드 -6014,기관계 -6021,증권순매수 -6022,보험순매수 -6023,투신순매수 -6024,은행순매수 -6025,종신금순매수 -6026,기금순매수 -6027,기타법인순매수 -6028,개인순매수 -6029,외국인순매수 -6030,내국인대우외국인순매수 -6032,국가순매수 -6033,사모펀드순매수 -6034,기관계순매수 -8000,개인투자자 -8002,결제잔고 -8003,결제금액 -8004,전일매도수량 -8005,전일매수수량 -8006,전일매도금액 -8007,전일매수금액 -8008,전일순매수량 -8018,손익 -8019,손익율 -8020,신용구분 -8021,대출일 -8040,평가금액 -8041,잔고구분 -8042,체결구분 -9001,종목코드 -9004,기준일자 -9019,근접율 -9026,회원사코드 -9201,계좌번호 -9203,주문번호 -9205,관리사번 -10010,시간외단일가_현재가 -10011,시간외단일가_전일대비 -10012,시간외단일가_등락률 -10013,시간외단일가_누적거래량 -10023,예상체결가 -10024,예상체결수량 -10025,시간외단일가_전일대비기호 -10041,시간외단일가_매도호가1 -10042,시간외단일가_매도호가2 -10043,시간외단일가_매도호가3 -10044,시간외단일가_매도호가4 -10045,시간외단일가_매도호가5 -10051,시간외단일가_매수호가1 -10052,시간외단일가_매수호가2 -10053,시간외단일가_매수호가3 -10054,시간외단일가_매수호가4 -10055,시간외단일가_매수호가5 -10061,시간외단일가_매도호가수량1 -10062,시간외단일가_매도호가수량2 -10063,시간외단일가_매도호가수량3 -10064,시간외단일가_매도호가수량4 -10065,시간외단일가_매도호가수량5 -10071,시간외단일가_매수호가수량1 -10072,시간외단일가_매수호가수량2 -10073,시간외단일가_매수호가수량3 -10074,시간외단일가_매수호가수량4 -10075,시간외단일가_매수호가수량5 -10081,시간외단일가_매도호가직전대비1 -10082,시간외단일가_매도호가직전대비2 -10083,시간외단일가_매도호가직전대비3 -10084,시간외단일가_매도호가직전대비4 -10085,시간외단일가_매도호가직전대비5 -10091,시간외단일가_매수호가직전대비1 -10092,시간외단일가_매수호가직전대비2 -10093,시간외단일가_매수호가직전대비3 -10094,시간외단일가_매수호가직전대비4 -10095,시간외단일가_매수호가직전대비5 -10121,시간외단일가_매도호가총잔량 -10125,시간외단일가_매수호가총잔량 -13000,평가손익 -28669,자본지지점 diff --git a/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.xlsx b/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.xlsx deleted file mode 100644 index 1bae746e..00000000 Binary files a/koapy/backend/kiwoom_open_api_plus/data/metadata/fid.xlsx and /dev/null differ diff --git a/koapy/backend/kiwoom_open_api_plus/data/metadata/realtype_by_desc.json b/koapy/backend/kiwoom_open_api_plus/data/metadata/realtype_by_desc.json deleted file mode 100644 index e69c7e1a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/metadata/realtype_by_desc.json +++ /dev/null @@ -1,4632 +0,0 @@ -{ - "CFD리얼잔고": { - "desc": "CFD리얼잔고", - "fids": [ - 9601, - 9602, - 24000, - 9201, - 9001, - 907, - 302, - 930, - 902, - 933, - 931, - 10, - 13005, - 13000, - 13001, - 9610, - 13006, - 13007, - 9611, - 8002, - 13090, - 13091, - 13907, - 50712, - 13310 - ], - "gidc": "2@", - "nfid": 25 - }, - "CFD리얼잔고총합": { - "desc": "CFD리얼잔고총합", - "fids": [ - 9201, - 13002, - 13008, - 13003, - 13009, - 950, - 13092, - 13098, - 13093, - 13099, - 13950 - ], - "gidc": "2#", - "nfid": 11 - }, - "CFD마진콜경고": { - "desc": "CFD마진콜경고", - "fids": [ - 24000, - 9201, - 9616, - 9617, - 9618, - 9619, - 9620, - 9621, - 8043 - ], - "gidc": "2$", - "nfid": 9 - }, - "CFD입출고": { - "desc": "CFD입출고", - "fids": [ - 24000, - 9623, - 9624, - 9201, - 9001, - 302, - 907, - 900, - 932, - 9609, - 9610, - 9611, - 9612, - 9613, - 9614, - 9615, - 10, - 950, - 8002, - 9605, - 50712 - ], - "gidc": "23", - "nfid": 21 - }, - "CFD주문": { - "desc": "CFD주문", - "fids": [ - 9601, - 9602, - 24000, - 9201, - 9203, - 9001, - 907, - 905, - 904, - 302, - 906, - 337, - 900, - 901, - 902, - 913, - 9603, - 908, - 9622, - 10, - 50712 - ], - "gidc": "20", - "nfid": 21 - }, - "CFD주문체결": { - "desc": "CFD주문체결", - "fids": [ - 9601, - 9602, - 24000, - 9201, - 9203, - 9001, - 907, - 905, - 904, - 302, - 906, - 337, - 900, - 901, - 902, - 909, - 911, - 9603, - 910, - 908, - 903, - 9622, - 10, - 9604, - 913, - 938, - 9605, - 9606, - 9607, - 9608, - 939, - 9609, - 9610, - 9611, - 9612, - 9613, - 9614, - 9615, - 950, - 914, - 13907, - 13908, - 50712, - 13310 - ], - "gidc": "2!", - "nfid": 44 - }, - "CFD체결": { - "desc": "CFD체결", - "fids": [ - 9601, - 9602, - 24000, - 9201, - 9203, - 9001, - 907, - 905, - 904, - 302, - 906, - 337, - 900, - 901, - 909, - 911, - 910, - 903, - 9604, - 913, - 902, - 938, - 9605, - 9606, - 9607, - 9608, - 939, - 9609, - 9610, - 9611, - 9612, - 9613, - 9614, - 9615, - 950, - 914, - 9622, - 10, - 50712 - ], - "gidc": "21", - "nfid": 39 - }, - "CME/EUREX주문": { - "desc": "CME/EUREX주문", - "fids": [ - 9201, - 9203, - 9001, - 907, - 905, - 904, - 906, - 900, - 901, - 902, - 913, - 908 - ], - "gidc": "F8", - "nfid": 12 - }, - "CME/EUREX체결": { - "desc": "CME/EUREX체결", - "fids": [ - 9201, - 9203, - 9001, - 907, - 905, - 904, - 906, - 900, - 901, - 911, - 910, - 13326, - 913, - 902, - 13327, - 13328, - 13006, - 13335, - 13336, - 13337, - 8009, - 930, - 13334, - 908, - 964, - 965, - 8018, - 8019 - ], - "gidc": "F9", - "nfid": 28 - }, - "CME미결제약정": { - "desc": "CME미결제약정", - "fids": [ - 195, - 181, - 196 - ], - "gidc": "Fc", - "nfid": 3 - }, - "CME미체결": { - "desc": "CME미체결", - "fids": [ - 9201, - 9203, - 9001, - 907, - 902, - 901, - 900, - 913, - 904, - 906, - 908, - 302, - 905, - 10 - ], - "gidc": "F+", - "nfid": 14 - }, - "CME배치": { - "desc": "CME배치", - "fids": [ - 13338, - 9201, - 9001, - 302, - 907, - 930, - 933, - 13000, - 13001, - 931, - 10, - 13004, - 13005, - 13006, - 13335, - 13336 - ], - "gidc": "FB", - "nfid": 16 - }, - "CME시세": { - "desc": "CME시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 25, - 197, - 26, - 246, - 247, - 248, - 30, - 196, - 22, - 50006, - 50001, - 845, - 848, - 846, - 849, - 847, - 850 - ], - "gidc": "FC", - "nfid": 36 - }, - "CME실시간잔고": { - "desc": "CME실시간잔고", - "fids": [ - 9201, - 9001, - 907, - 930, - 933, - 931, - 10, - 13000, - 13001, - 13004, - 13005, - 13006, - 302 - ], - "gidc": "F<", - "nfid": 13 - }, - "CME잔고합": { - "desc": "CME잔고합", - "fids": [ - 9201, - 13002, - 13003, - 8018, - 8019, - 13008, - 13009 - ], - "gidc": "F>", - "nfid": 7 - }, - "CME호가잔량": { - "desc": "CME호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 13 - ], - "gidc": "FD", - "nfid": 52 - }, - "ECN주식당일거래원": { - "desc": "ECN주식당일거래원", - "fids": [ - 10141, - 10161, - 10151, - 10171, - 10142, - 10162, - 10152, - 10172, - 10143, - 10163, - 10153, - 10173, - 10144, - 10164, - 10154, - 10174, - 10145, - 10165, - 10155, - 10175 - ], - "gidc": "0f", - "nfid": 20 - }, - "ECN주식시간외호가": { - "desc": "ECN주식시간외호가", - "fids": [ - 10021, - 10131, - 10132, - 10135, - 10136 - ], - "gidc": "0e", - "nfid": 5 - }, - "ECN주식시세": { - "desc": "ECN주식시세", - "fids": [ - 10010, - 10011, - 10012, - 10027, - 10028, - 10013, - 10014, - 10016, - 10017, - 10018, - 10025 - ], - "gidc": "0a", - "nfid": 11 - }, - "ECN주식우선호가": { - "desc": "ECN주식우선호가", - "fids": [ - 10027, - 10028 - ], - "gidc": "0c", - "nfid": 2 - }, - "ECN주식체결": { - "desc": "ECN주식체결", - "fids": [ - 10020, - 10010, - 10011, - 10012, - 10027, - 10028, - 10015, - 10013, - 10014, - 10016, - 10017, - 10018, - 10025 - ], - "gidc": "0b", - "nfid": 13 - }, - "ECN주식호가잔량": { - "desc": "ECN주식호가잔량", - "fids": [ - 10021, - 10041, - 10042, - 10043, - 10044, - 10045, - 10061, - 10062, - 10063, - 10064, - 10065, - 10081, - 10082, - 10083, - 10084, - 10085, - 10051, - 10052, - 10053, - 10054, - 10055, - 10071, - 10072, - 10073, - 10074, - 10075, - 10091, - 10092, - 10093, - 10094, - 10095, - 10121, - 10122, - 10125, - 10126, - 10023, - 10024, - 10035, - 10033, - 10034, - 10128 - ], - "gidc": "0d", - "nfid": 41 - }, - "ELW 이론가": { - "desc": "ELW 이론가", - "fids": [ - 20, - 10, - 670, - 671, - 672, - 673, - 674, - 675, - 676, - 706 - ], - "gidc": "0m", - "nfid": 10 - }, - "ELW 지표": { - "desc": "ELW 지표", - "fids": [ - 20, - 666, - 1211, - 667, - 668, - 669 - ], - "gidc": "0u", - "nfid": 6 - }, - "ETF NAV": { - "desc": "ETF NAV", - "fids": [ - 36, - 37, - 38, - 39, - 20, - 10, - 11, - 12, - 13, - 25, - 768, - 769, - 770, - 265, - 266 - ], - "gidc": "0G", - "nfid": 15 - }, - "EUF시세": { - "desc": "EUF시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 25, - 197, - 26, - 246, - 247, - 248, - 30, - 196, - 22, - 50006, - 50001, - 845, - 848, - 846, - 849, - 847, - 850 - ], - "gidc": "fU", - "nfid": 36 - }, - "EUF호가잔량": { - "desc": "EUF호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 13, - 23, - 238, - 200, - 201 - ], - "gidc": "fu", - "nfid": 56 - }, - "EUREX배치": { - "desc": "EUREX배치", - "fids": [ - 13338, - 9201, - 9001, - 302, - 907, - 930, - 933, - 13000, - 13001, - 931, - 10, - 13004, - 13005, - 13006, - 13335, - 13336 - ], - "gidc": "Fb", - "nfid": 16 - }, - "EUREX시세": { - "desc": "EUREX시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 16, - 17, - 18, - 187, - 188, - 25, - 197, - 26, - 30, - 22, - 50001, - 845, - 848, - 846, - 849, - 847, - 850 - ], - "gidc": "FU", - "nfid": 25 - }, - "EUREX호가": { - "desc": "EUREX호가", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 51, - 71, - 91, - 42, - 62, - 82, - 52, - 72, - 92, - 43, - 63, - 83, - 53, - 73, - 93, - 121, - 122, - 125, - 126, - 137, - 128, - 13, - 23, - 238, - 200, - 201 - ], - "gidc": "Fu", - "nfid": 32 - }, - "TS고저변경": { - "desc": "TS고저변경", - "fids": [ - 1223, - 1225, - 1751, - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1722, - 1724, - 1725 - ], - "gidc": "13", - "nfid": 12 - }, - "VI발동/해제": { - "desc": "VI발동/해제", - "fids": [ - 9001, - 302, - 13, - 14, - 9068, - 9008, - 9075, - 1221, - 1223, - 1224, - 1225, - 1236, - 1237, - 1238, - 1239, - 1489, - 1490, - 9069, - 1279 - ], - "gidc": "1h", - "nfid": 19 - }, - "VI발동/해제-종목별": { - "desc": "VI발동/해제-종목별", - "fids": [ - 13, - 14, - 9068, - 9008, - 9075, - 1221, - 1223, - 1224, - 1225, - 1236, - 1237, - 1238, - 1239 - ], - "gidc": "1z", - "nfid": 13 - }, - "VI정적예상가": { - "desc": "VI정적예상가", - "fids": [ - 1229, - 1227, - 1228, - 1487, - 1488 - ], - "gidc": "1y", - "nfid": 5 - }, - "X-Ray순간체결량": { - "desc": "X-Ray순간체결량", - "fids": [ - 302, - 9001, - 20, - 10, - 260, - 23, - 700, - 346, - 15, - 13, - 12, - 11, - 25, - 701, - 702, - 703, - 704, - 705, - 706 - ], - "gidc": "0n", - "nfid": 19 - }, - "기준가변경": { - "desc": "기준가변경", - "fids": [ - 1223, - 1225, - 1751, - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1706, - 1710, - 1714, - 1718, - 1722, - 1725 - ], - "gidc": "15", - "nfid": 15 - }, - "대주가능수량": { - "desc": "대주가능수량", - "fids": [ - 857 - ], - "gidc": "1g", - "nfid": 1 - }, - "데이터셋실시간": { - "desc": "데이터셋실시간", - "fids": [ - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 305, - 306, - 10, - 16, - 17, - 18, - 14, - 307, - 857 - ], - "gidc": "0+", - "nfid": 29 - }, - "리얼잔고": { - "desc": "리얼잔고", - "fids": [ - 9201, - 9001, - 917, - 916, - 302, - 13000, - 13001, - 930, - 931, - 932, - 8002, - 10, - 8008, - 945, - 13004, - 13005, - 13006, - 13007, - 950, - 946, - 951, - 27, - 28, - 933, - 307, - 8019, - 957, - 958, - 918, - 990, - 991, - 992, - 993, - 13049, - 13050, - 13037, - 13054, - 13081, - 13090, - 13091, - 306, - 305, - 13092, - 959, - 13093, - 397, - 925, - 926, - 924, - 10010, - 13149, - 13150, - 13151, - 13160, - 13161, - 25, - 11, - 12 - ], - "gidc": "0\"", - "nfid": 58 - }, - "리얼잔고총합": { - "desc": "리얼잔고총합", - "fids": [ - 9201, - 13002, - 13003, - 13008, - 13009, - 950, - 13047, - 13048, - 13051, - 13052, - 13053, - 8019, - 990, - 991, - 992, - 993, - 13082, - 13083, - 13084, - 13085, - 13086, - 13087, - 13088, - 13089, - 13152, - 13153, - 13154 - ], - "gidc": "0#", - "nfid": 27 - }, - "매입인도체결": { - "desc": "매입인도체결", - "fids": [ - 12010, - 12011, - 12012, - 12015, - 12025, - 12030, - 12305, - 12306 - ], - "gidc": "0Y", - "nfid": 8 - }, - "매입인도호가": { - "desc": "매입인도호가", - "fids": [ - 12023, - 12024, - 12030, - 12035, - 12200, - 12201, - 12021, - 12121, - 12125, - 12041, - 12061, - 12051, - 12071, - 12042, - 12062, - 12052, - 12072, - 12043, - 12063, - 12053, - 12073 - ], - "gidc": "0y", - "nfid": 21 - }, - "멀티차단": { - "desc": "멀티차단", - "fids": [ - 1337, - 20018, - 20055, - 20116, - 20017 - ], - "gidc": "16", - "nfid": 5 - }, - "모니터링 실시간LOG": { - "desc": "모니터링 실시간LOG", - "fids": [ - 9001, - 20000, - 20001, - 20002, - 20003, - 20010 - ], - "gidc": "0@", - "nfid": 6 - }, - "미국입출고": { - "desc": "미국입출고", - "fids": [ - 9064, - 9201, - 9001, - 900, - 901, - 13303, - 13094, - 13095, - 50005, - 8043, - 302 - ], - "gidc": "FM", - "nfid": 11 - }, - "미국종목변경": { - "desc": "미국종목변경", - "fids": [ - 9201, - 90011, - 3334, - 900, - 901, - 13303, - 50005, - 8043, - 50340, - 302 - ], - "gidc": "FN", - "nfid": 10 - }, - "미체결통보시스템": { - "desc": "미체결통보시스템", - "fids": [ - 9201, - 986, - 987, - 988, - 989, - 9001, - 916, - 917, - 9203, - 900, - 901 - ], - "gidc": "1m", - "nfid": 11 - }, - "배치데이터갱신": { - "desc": "배치데이터갱신", - "fids": [ - 4384, - 20003 - ], - "gidc": "FR", - "nfid": 2 - }, - "분할반복주문": { - "desc": "분할반복주문", - "fids": [ - 1745, - 1703, - 8083, - 1337, - 24031, - 24032, - 9001, - 1734, - 9204, - 1754, - 8076, - 8077, - 1765, - 7101, - 1934, - 1937, - 8078, - 8079, - 8080 - ], - "gidc": "D1", - "nfid": 19 - }, - "빅데이터급상승": { - "desc": "빅데이터급상승", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1903, - 1904, - 1905 - ], - "gidc": "1X", - "nfid": 7 - }, - "빅데이터뉴스": { - "desc": "빅데이터뉴스", - "fids": [ - 225, - 777, - 222, - 223, - 9001, - 302, - 224, - 20, - 22, - 249, - 250, - 1901, - 1902, - 7102, - 7103, - 1900 - ], - "gidc": "1W", - "nfid": 16 - }, - "빅데이터종목10분": { - "desc": "빅데이터종목10분", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1900, - 1901, - 1902, - 1903, - 1904, - 1905, - 1906, - 1907 - ], - "gidc": "1S", - "nfid": 12 - }, - "빅데이터종목1분": { - "desc": "빅데이터종목1분", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1900, - 1901, - 1902, - 1903, - 1904, - 1905, - 1906, - 1907 - ], - "gidc": "1R", - "nfid": 12 - }, - "빅데이터종목1시간": { - "desc": "빅데이터종목1시간", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1900, - 1901, - 1902, - 1903, - 1904, - 1905, - 1906, - 1907 - ], - "gidc": "1T", - "nfid": 12 - }, - "빅데이터종목30초": { - "desc": "빅데이터종목30초", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1900, - 1901, - 1902, - 1903, - 1904, - 1905, - 1906, - 1907 - ], - "gidc": "1Y", - "nfid": 12 - }, - "빅데이터종목당일": { - "desc": "빅데이터종목당일", - "fids": [ - 7102, - 7103, - 9001, - 302, - 1900, - 1901, - 1902, - 1903, - 1904, - 1905, - 1906, - 1907 - ], - "gidc": "1U", - "nfid": 12 - }, - "상하한가폭변경": { - "desc": "상하한가폭변경", - "fids": [ - 401, - 802, - 803, - 804, - 805, - 806, - 807 - ], - "gidc": "1s", - "nfid": 7 - }, - "선물기초자산시세": { - "desc": "선물기초자산시세", - "fids": [ - 10, - 25, - 11, - 12 - ], - "gidc": "0I", - "nfid": 4 - }, - "선물시세": { - "desc": "선물시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 25, - 197, - 26, - 246, - 247, - 248, - 30, - 196, - 845, - 848, - 846, - 849, - 847, - 850, - 851, - 1365, - 1366, - 1367, - 305, - 306, - 228, - 232, - 234, - 236 - ], - "gidc": "0K", - "nfid": 43 - }, - "선물옵션우선호가": { - "desc": "선물옵션우선호가", - "fids": [ - 10, - 27, - 28 - ], - "gidc": "0r", - "nfid": 3 - }, - "선물옵션합계": { - "desc": "선물옵션합계", - "fids": [ - 9201, - 13010, - 13011, - 13012, - 13013, - 13014, - 13015, - 13016, - 13017, - 13018, - 13019, - 13020, - 13021, - 13022, - 13023, - 13024, - 13025, - 13026, - 13027, - 13028, - 13029 - ], - "gidc": "0%", - "nfid": 21 - }, - "선물이론가": { - "desc": "선물이론가", - "fids": [ - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 246, - 247, - 248 - ], - "gidc": "0k", - "nfid": 10 - }, - "선물호가잔량": { - "desc": "선물호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 13, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "0L", - "nfid": 60 - }, - "소액채권체결": { - "desc": "소액채권체결", - "fids": [ - 20, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 25 - ], - "gidc": "1c", - "nfid": 11 - }, - "소액채권호가잔량": { - "desc": "소액채권호가잔량", - "fids": [ - 41, - 61, - 51, - 71, - 722, - 727, - 42, - 62, - 52, - 72, - 723, - 728, - 43, - 63, - 53, - 73, - 724, - 729, - 44, - 64, - 54, - 74, - 725, - 730, - 45, - 65, - 55, - 75, - 726, - 731, - 121, - 125 - ], - "gidc": "1d", - "nfid": 32 - }, - "수동자동주문": { - "desc": "수동자동주문", - "fids": [ - 1223, - 1225, - 1751, - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1744, - 1753, - 1754, - 1727, - 907, - 1728, - 1729, - 1730, - 1731, - 1704, - 1722, - 1724, - 1725, - 1757, - 10, - 1759, - 1758 - ], - "gidc": "11", - "nfid": 26 - }, - "순간체결량": { - "desc": "순간체결량", - "fids": [ - 20, - 9001, - 302, - 10, - 25, - 11, - 12, - 15, - 13, - 30, - 14, - 1313 - ], - "gidc": "08", - "nfid": 12 - }, - "스톱로스": { - "desc": "스톱로스", - "fids": [ - 9201, - 9001, - 13200, - 13201, - 13202, - 13203, - 13204, - 13205, - 13230, - 13231, - 13232, - 13233, - 13222, - 13223, - 13220, - 13221, - 13224 - ], - "gidc": "0$", - "nfid": 17 - }, - "스톱주문": { - "desc": "스톱주문", - "fids": [ - 9201, - 9001, - 302, - 13200, - 13201, - 13202, - 13203, - 13204, - 13205, - 13220, - 13221, - 13222, - 13212, - 13213, - 13214, - 907 - ], - "gidc": "0&", - "nfid": 16 - }, - "시간외종목정보": { - "desc": "시간외종목정보", - "fids": [ - 10297, - 10305, - 10306, - 10307 - ], - "gidc": "0i", - "nfid": 4 - }, - "시황/뉴스": { - "desc": "시황/뉴스", - "fids": [ - 225, - 777, - 222, - 223, - 9001, - 302, - 224, - 20, - 22, - 249, - 250, - 9407 - ], - "gidc": "0T", - "nfid": 12 - }, - "신호관리자투자정보": { - "desc": "신호관리자투자정보", - "fids": [ - 841, - 9001, - 20, - 225, - 701, - 302, - 224 - ], - "gidc": "1B", - "nfid": 7 - }, - "실시간상하한가": { - "desc": "실시간상하한가", - "fids": [ - 1365, - 1366, - 305, - 306 - ], - "gidc": "0V", - "nfid": 4 - }, - "실시간증거금": { - "desc": "실시간증거금", - "fids": [ - 9201, - 8048, - 8049, - 8050, - 8051, - 8052, - 8053, - 8054, - 8055, - 8056, - 8057, - 8058, - 8059, - 8060, - 8061, - 8062, - 8066, - 8063, - 8064, - 8065 - ], - "gidc": "0-", - "nfid": 20 - }, - "알-TS변경": { - "desc": "알-TS변경", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 9001, - 6606, - 1223, - 1722, - 1725, - 13221, - 1719 - ], - "gidc": "41", - "nfid": 13 - }, - "알-감시시작": { - "desc": "알-감시시작", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 1225, - 1733, - 14006, - 9400 - ], - "gidc": "36", - "nfid": 10 - }, - "알-내조건식수정": { - "desc": "알-내조건식수정", - "fids": [ - 20000, - 1225, - 6601 - ], - "gidc": "37", - "nfid": 3 - }, - "알-매도감시시작": { - "desc": "알-매도감시시작", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 9001, - 6606, - 1225, - 14004, - 14005 - ], - "gidc": "31", - "nfid": 11 - }, - "알-매도감시포착": { - "desc": "알-매도감시포착", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 9001, - 6606, - 1223, - 1757, - 14004, - 14005, - 6610, - 1704, - 1705, - 1706, - 1714, - 1722, - 1725, - 13221, - 1225, - 1719 - ], - "gidc": "32", - "nfid": 22 - }, - "알-멀티차단": { - "desc": "알-멀티차단", - "fids": [ - 1337, - 20018, - 20055, - 20116, - 20017 - ], - "gidc": "40", - "nfid": 5 - }, - "알-모의 리얼잔고": { - "desc": "알-모의 리얼잔고", - "fids": [ - 9201, - 9001, - 302, - 13000, - 13001, - 930, - 931, - 932, - 10, - 13004, - 13005, - 13006, - 13007, - 950, - 951, - 933, - 8019, - 13092, - 13037 - ], - "gidc": "3\"", - "nfid": 19 - }, - "알-모의 주문체결": { - "desc": "알-모의 주문체결", - "fids": [ - 9201, - 9203, - 9205, - 9001, - 912, - 913, - 302, - 900, - 901, - 902, - 903, - 904, - 905, - 906, - 907, - 908, - 909, - 910, - 911, - 10, - 27, - 28, - 914, - 915, - 938, - 939, - 919, - 920, - 921, - 922, - 923, - 949, - 10010, - 13312, - 13313, - 8000, - 985 - ], - "gidc": "3!", - "nfid": 37 - }, - "알-모의리얼잔고총합": { - "desc": "알-모의리얼잔고총합", - "fids": [ - 9201, - 13002, - 13003, - 13008, - 13009, - 950, - 13047, - 13048, - 13051, - 13052, - 13053, - 8019, - 990, - 991, - 992, - 993, - 13082, - 13083, - 13084, - 13085, - 13086, - 13087, - 13088, - 13089, - 13152, - 13153, - 13154 - ], - "gidc": "3#", - "nfid": 27 - }, - "알-모의주문체결": { - "desc": "알-모의주문체결", - "fids": [ - 9201, - 9203, - 9205, - 9001, - 912, - 913, - 302, - 900, - 901, - 902, - 903, - 904, - 905, - 906, - 907, - 908, - 909, - 910, - 911, - 10, - 27, - 28, - 914, - 915, - 938, - 939, - 919, - 920, - 921, - 922, - 923, - 949, - 10010 - ], - "gidc": "3a", - "nfid": 33 - }, - "알-모의현물잔고": { - "desc": "알-모의현물잔고", - "fids": [ - 9201, - 9001, - 917, - 916, - 302, - 10, - 930, - 931, - 932, - 933, - 945, - 946, - 950, - 951, - 27, - 28, - 307, - 8019, - 957, - 958, - 918, - 990, - 991, - 992, - 993, - 959, - 924, - 10010, - 25, - 11, - 12 - ], - "gidc": "3c", - "nfid": 31 - }, - "알-제한여부": { - "desc": "알-제한여부", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 14028, - 1225 - ], - "gidc": "39", - "nfid": 8 - }, - "알-종목포착이탈": { - "desc": "알-종목포착이탈", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 9001, - 1225, - 1223, - 6610 - ], - "gidc": "30", - "nfid": 10 - }, - "알-주문결과": { - "desc": "알-주문결과", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 9001, - 6606, - 1225, - 14004, - 14005, - 1760, - 1223, - 14006, - 1753, - 1754, - 9203, - 1727, - 1729, - 1731, - 905, - 910, - 911, - 13005, - 908, - 1752, - 1755 - ], - "gidc": "33", - "nfid": 27 - }, - "알-주문조건수정": { - "desc": "알-주문조건수정", - "fids": [ - 20000, - 1225, - 6604, - 6601, - 6605, - 6611, - 14007, - 14008, - 14009, - 14010, - 14011, - 14012, - 14013, - 14014, - 14015, - 14016, - 14017, - 14018, - 14019, - 14021, - 14022, - 14023, - 14024, - 14025, - 14026, - 14027, - 14028, - 14029, - 8011, - 6631, - 6632, - 6523, - 14030, - 1707, - 1708, - 1709, - 1715, - 1716, - 1717, - 14031, - 14032, - 8014, - 14033, - 14034, - 14035, - 14036 - ], - "gidc": "38", - "nfid": 46 - }, - "알-청산시작": { - "desc": "알-청산시작", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 1225 - ], - "gidc": "34", - "nfid": 7 - }, - "알-청산완료": { - "desc": "알-청산완료", - "fids": [ - 14037, - 20000, - 1745, - 1703, - 24031, - 24032, - 1225 - ], - "gidc": "35", - "nfid": 7 - }, - "업종등락": { - "desc": "업종등락", - "fids": [ - 20, - 252, - 251, - 253, - 255, - 254, - 13, - 14, - 10, - 11, - 12, - 256, - 257, - 25 - ], - "gidc": "0U", - "nfid": 14 - }, - "업종지수": { - "desc": "업종지수", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 14, - 16, - 17, - 18, - 25, - 26 - ], - "gidc": "0J", - "nfid": 12 - }, - "예상업종지수": { - "desc": "예상업종지수", - "fids": [ - 20, - 291, - 292, - 294, - 295, - 293, - 9075 - ], - "gidc": "0x", - "nfid": 7 - }, - "예수금": { - "desc": "예수금", - "fids": [ - 9201, - 13055, - 13056, - 13069, - 13067, - 13068, - 13070, - 951, - 8006, - 8007, - 935, - 937, - 952, - 953, - 954, - 955, - 956, - 8043 - ], - "gidc": "0'", - "nfid": 18 - }, - "옵션시세": { - "desc": "옵션시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 186, - 190, - 191, - 193, - 192, - 194, - 181, - 25, - 26, - 137, - 187, - 197, - 246, - 247, - 248, - 219, - 196, - 188, - 189, - 30, - 391, - 392, - 393, - 845, - 848, - 846, - 849, - 847, - 850, - 851, - 1365, - 1366, - 1367, - 305, - 306, - 228, - 232, - 234, - 236 - ], - "gidc": "0O", - "nfid": 53 - }, - "옵션이론가": { - "desc": "옵션이론가", - "fids": [ - 195, - 182, - 186, - 190, - 191, - 193, - 192, - 194, - 181, - 246, - 247, - 248, - 187, - 188, - 189 - ], - "gidc": "0l", - "nfid": 15 - }, - "옵션호가잔량": { - "desc": "옵션호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 13, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "0P", - "nfid": 60 - }, - "일반신호": { - "desc": "일반신호", - "fids": [ - 841, - 9001, - 302, - 907, - 20, - 840, - 842 - ], - "gidc": "03", - "nfid": 7 - }, - "임의연장정보": { - "desc": "임의연장정보", - "fids": [ - 580, - 581, - 582, - 583, - 584, - 585, - 586, - 587, - 588, - 589 - ], - "gidc": "0h", - "nfid": 10 - }, - "자동주문결과": { - "desc": "자동주문결과", - "fids": [ - 1223, - 1225, - 1751, - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1753, - 1754, - 1735, - 1727, - 907, - 1729, - 1731, - 9203, - 910, - 911, - 903, - 908, - 1752, - 1755, - 1760, - 1759, - 1757, - 1704, - 1705, - 1738, - 1741, - 1740, - 1739, - 1722, - 1706, - 1725, - 1710 - ], - "gidc": "12", - "nfid": 36 - }, - "자유포멧": { - "desc": "자유포멧", - "fids": [], - "gidc": "0~", - "nfid": 0 - }, - "자체업종지수": { - "desc": "자체업종지수", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 14, - 41, - 51, - 25 - ], - "gidc": "0X", - "nfid": 10 - }, - "잔고청산삭제": { - "desc": "잔고청산삭제", - "fids": [ - 1223, - 1225, - 1751, - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1758 - ], - "gidc": "17", - "nfid": 10 - }, - "잔고편입": { - "desc": "잔고편입", - "fids": [ - 1337, - 1745, - 1703, - 24031, - 24032, - 9001, - 1700, - 1701, - 1702, - 1704, - 1705, - 1706, - 1707, - 1708, - 1709, - 1710, - 1711, - 1712, - 1713, - 1714, - 1715, - 1716, - 1717, - 1718, - 1719, - 1720, - 1721, - 1722, - 1723, - 1724, - 1725, - 1726, - 1727, - 907, - 1728, - 1729, - 1730, - 1731, - 1732, - 1744, - 916 - ], - "gidc": "14", - "nfid": 41 - }, - "장시작시간": { - "desc": "장시작시간", - "fids": [ - 215, - 20, - 214 - ], - "gidc": "0s", - "nfid": 3 - }, - "조건검색": { - "desc": "조건검색", - "fids": [ - 841, - 9001, - 843, - 20, - 907 - ], - "gidc": "02", - "nfid": 5 - }, - "종목마스터갱신": { - "desc": "종목마스터갱신", - "fids": [ - 4384, - 20003 - ], - "gidc": "Fr", - "nfid": 2 - }, - "종목별프로그램매매": { - "desc": "종목별프로그램매매", - "fids": [ - 20, - 10, - 25, - 11, - 12, - 13, - 202, - 204, - 206, - 208, - 210, - 212, - 213, - 211, - 928, - 929, - 502, - 505, - 511, - 514, - 523, - 522, - 549, - 548, - 571, - 570, - 526, - 529, - 535, - 538, - 547, - 546, - 551, - 550, - 573, - 572, - 14 - ], - "gidc": "0w", - "nfid": 37 - }, - "종목별프로그램매매2": { - "desc": "종목별프로그램매매2", - "fids": [ - 1188, - 1189 - ], - "gidc": "1w", - "nfid": 2 - }, - "종목투자자(거래소)": { - "desc": "종목투자자(거래소)", - "fids": [ - 7103, - 22, - 1800, - 1801, - 1802, - 1803, - 1804, - 1805, - 1806, - 1807, - 1808, - 1809, - 1810, - 1811, - 1812, - 1813, - 1814, - 1815, - 1816, - 1817, - 1818, - 1819, - 1820, - 1821, - 1822, - 1823, - 1824, - 1825, - 1826, - 1827, - 1828, - 1829, - 1830, - 1831, - 1832, - 1833, - 1834, - 1835, - 1836, - 1837, - 1838, - 1839, - 1840, - 1841, - 1842, - 1843, - 1844, - 1845, - 1846, - 1847, - 1848, - 1849, - 1850, - 1851, - 1852, - 1853, - 1854, - 1855, - 1856, - 1857, - 1858, - 1859, - 1960, - 1961, - 1962, - 1963, - 1964, - 1965, - 1966, - 1967, - 1968, - 1969, - 1970, - 1971, - 1972, - 1973, - 1974, - 1975, - 1976, - 1977, - 1454, - 1455, - 1456, - 1457, - 263, - 261, - 267, - 1263, - 1261, - 1267 - ], - "gidc": "2I", - "nfid": 90 - }, - "종목투자자(잠정)": { - "desc": "종목투자자(잠정)", - "fids": [ - 7103, - 22, - 1800, - 1801, - 1802, - 1803, - 1804, - 1805, - 1806, - 1807, - 1808, - 1809, - 1810, - 1811, - 1812, - 1813, - 1814, - 1815, - 1816, - 1817, - 1818, - 1819, - 1820, - 1821, - 1822, - 1823, - 1824, - 1825, - 1826, - 1827, - 1828, - 1829, - 1830, - 1831, - 1832, - 1833, - 1834, - 1835, - 1836, - 1837, - 1838, - 1839, - 1840, - 1841, - 1842, - 1843, - 1844, - 1845, - 1846, - 1847, - 1848, - 1849, - 1850, - 1851, - 1852, - 1853, - 1854, - 1855, - 1856, - 1857, - 1858, - 1859, - 1960, - 1961, - 1962, - 1963, - 1964, - 1965, - 1966, - 1967, - 1968, - 1969, - 1970, - 1971, - 1972, - 1973, - 1974, - 1975, - 1976, - 1977, - 1450, - 1451, - 1452, - 1453, - 263, - 261, - 267, - 1263, - 1261, - 1267 - ], - "gidc": "1I", - "nfid": 90 - }, - "주문체결": { - "desc": "주문체결", - "fids": [ - 9201, - 9203, - 9205, - 9001, - 912, - 913, - 302, - 900, - 901, - 902, - 903, - 904, - 905, - 906, - 907, - 908, - 909, - 910, - 911, - 10, - 27, - 28, - 914, - 915, - 938, - 939, - 919, - 920, - 921, - 922, - 923, - 949, - 10010, - 969, - 13312, - 13313, - 8000, - 985 - ], - "gidc": "0!", - "nfid": 38 - }, - "주문체결서버상태": { - "desc": "주문체결서버상태", - "fids": [ - 961, - 962, - 963, - 966, - 967 - ], - "gidc": "09", - "nfid": 5 - }, - "주식거래원": { - "desc": "주식거래원", - "fids": [ - 9001, - 9026, - 302, - 334, - 20, - 203, - 207, - 210, - 211, - 260, - 337, - 10, - 11, - 12, - 25, - 1319 - ], - "gidc": "0Q", - "nfid": 16 - }, - "주식거래원(1LINE)": { - "desc": "주식거래원(1LINE)", - "fids": [ - 9001, - 9026, - 302, - 334, - 20, - 203, - 207, - 210, - 211, - 213, - 337, - 10, - 11, - 12, - 25 - ], - "gidc": "1Q", - "nfid": 15 - }, - "주식당일거래원": { - "desc": "주식당일거래원", - "fids": [ - 141, - 161, - 166, - 146, - 271, - 151, - 171, - 176, - 156, - 281, - 142, - 162, - 167, - 147, - 272, - 152, - 172, - 177, - 157, - 282, - 143, - 163, - 168, - 148, - 273, - 153, - 173, - 178, - 158, - 283, - 144, - 164, - 169, - 149, - 274, - 154, - 174, - 179, - 159, - 284, - 145, - 165, - 170, - 150, - 275, - 155, - 175, - 180, - 160, - 285, - 261, - 262, - 263, - 264, - 267, - 268, - 337, - 13, - 1861, - 1862, - 1863, - 1864, - 1865, - 1871, - 1872, - 1873, - 1874, - 1875, - 1261, - 1263, - 1267, - 1876, - 1877, - 1878, - 1879, - 1880, - 1881, - 1882, - 1883, - 1884, - 1885, - 1264, - 1265, - 1266, - 1886, - 1887, - 1888, - 1889 - ], - "gidc": "0F", - "nfid": 88 - }, - "주식상하한": { - "desc": "주식상하한", - "fids": [ - 9001, - 302, - 10, - 25, - 11, - 12, - 13, - 30, - 9076, - 61, - 71, - 333, - 14 - ], - "gidc": "1A", - "nfid": 13 - }, - "주식선물호가잔량": { - "desc": "주식선물호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 46, - 66, - 86, - 106, - 56, - 76, - 96, - 116, - 47, - 67, - 87, - 107, - 57, - 77, - 97, - 117, - 48, - 68, - 88, - 108, - 58, - 78, - 98, - 118, - 49, - 69, - 89, - 109, - 59, - 79, - 99, - 119, - 50, - 70, - 90, - 110, - 60, - 80, - 100, - 120, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "0N", - "nfid": 99 - }, - "주식시간외호가": { - "desc": "주식시간외호가", - "fids": [ - 21, - 131, - 132, - 135, - 136 - ], - "gidc": "0E", - "nfid": 5 - }, - "주식시세": { - "desc": "주식시세", - "fids": [ - 10, - 11, - 12, - 27, - 28, - 13, - 14, - 16, - 17, - 18, - 25, - 26, - 29, - 30, - 31, - 32, - 311, - 822, - 567, - 568, - 732, - 852 - ], - "gidc": "0A", - "nfid": 22 - }, - "주식예상체결": { - "desc": "주식예상체결", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 25 - ], - "gidc": "0H", - "nfid": 7 - }, - "주식옵션시세": { - "desc": "주식옵션시세", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 186, - 190, - 191, - 193, - 192, - 194, - 181, - 25, - 26, - 845, - 848, - 846, - 849, - 847, - 850, - 851, - 1365, - 1366, - 1367, - 305, - 306, - 197, - 196, - 232, - 234, - 236 - ], - "gidc": "0o", - "nfid": 40 - }, - "주식옵션이론가": { - "desc": "주식옵션이론가", - "fids": [ - 195, - 182, - 186, - 190, - 191, - 193, - 192, - 194, - 181 - ], - "gidc": "0q", - "nfid": 9 - }, - "주식옵션호가잔량": { - "desc": "주식옵션호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 42, - 43, - 44, - 45, - 61, - 62, - 63, - 64, - 65, - 101, - 102, - 103, - 104, - 105, - 51, - 52, - 53, - 54, - 55, - 71, - 72, - 73, - 74, - 75, - 111, - 112, - 113, - 114, - 115, - 121, - 123, - 125, - 127, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "0p", - "nfid": 45 - }, - "주식우선호가": { - "desc": "주식우선호가", - "fids": [ - 27, - 28 - ], - "gidc": "0C", - "nfid": 2 - }, - "주식종목정보": { - "desc": "주식종목정보", - "fids": [ - 297, - 592, - 593, - 305, - 306, - 307, - 689, - 594, - 382, - 370, - 330, - 300, - 1491 - ], - "gidc": "0g", - "nfid": 13 - }, - "주식체결": { - "desc": "주식체결", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 25, - 26, - 29, - 30, - 31, - 32, - 228, - 311, - 290, - 691, - 822, - 567, - 568, - 851, - 1890, - 1891, - 1892, - 1030, - 1031, - 1032, - 1071, - 1072, - 1313, - 1315, - 1316, - 1314, - 1497, - 1498, - 620, - 732, - 852 - ], - "gidc": "0B", - "nfid": 43 - }, - "주식호가잔량": { - "desc": "주식호가잔량", - "fids": [ - 21, - 41, - 61, - 81, - 51, - 71, - 91, - 42, - 62, - 82, - 52, - 72, - 92, - 43, - 63, - 83, - 53, - 73, - 93, - 44, - 64, - 84, - 54, - 74, - 94, - 45, - 65, - 85, - 55, - 75, - 95, - 46, - 66, - 86, - 56, - 76, - 96, - 47, - 67, - 87, - 57, - 77, - 97, - 48, - 68, - 88, - 58, - 78, - 98, - 49, - 69, - 89, - 59, - 79, - 99, - 50, - 70, - 90, - 60, - 80, - 100, - 121, - 122, - 125, - 126, - 23, - 24, - 128, - 129, - 138, - 139, - 200, - 201, - 238, - 291, - 292, - 293, - 294, - 295, - 621, - 631, - 622, - 632, - 623, - 633, - 624, - 634, - 625, - 635, - 626, - 636, - 627, - 637, - 628, - 638, - 629, - 639, - 630, - 640, - 13, - 299, - 215, - 216 - ], - "gidc": "0D", - "nfid": 103 - }, - "증거금": { - "desc": "증거금", - "fids": [ - 9201, - 8048, - 8049, - 8050, - 8051, - 8052, - 8053, - 8054, - 8055, - 8056, - 8057, - 8058, - 8059, - 8060, - 8061, - 8062, - 8066, - 8063, - 8064, - 8065 - ], - "gidc": "0v", - "nfid": 20 - }, - "채권체결": { - "desc": "채권체결", - "fids": [ - 20, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 25 - ], - "gidc": "1a", - "nfid": 11 - }, - "채권호가잔량": { - "desc": "채권호가잔량", - "fids": [ - 41, - 61, - 51, - 71, - 722, - 727, - 42, - 62, - 52, - 72, - 723, - 728, - 43, - 63, - 53, - 73, - 724, - 729, - 44, - 64, - 54, - 74, - 725, - 730, - 45, - 65, - 55, - 75, - 726, - 731, - 121, - 125 - ], - "gidc": "1b", - "nfid": 32 - }, - "채널K실시간티커": { - "desc": "채널K실시간티커", - "fids": [ - 225, - 221, - 223, - 22, - 20, - 224, - 249, - 777, - 250, - 9406 - ], - "gidc": "1C", - "nfid": 10 - }, - "코넥스경매매체결": { - "desc": "코넥스경매매체결", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 14, - 25 - ], - "gidc": "0W", - "nfid": 8 - }, - "투자자ticker": { - "desc": "투자자ticker", - "fids": [ - 6028, - 6029, - 6034, - 886, - 887, - 888 - ], - "gidc": "0Z", - "nfid": 6 - }, - "투자자별매매": { - "desc": "투자자별매매", - "fids": [ - 20, - 217, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 561, - 562, - 50401, - 50420, - 50403, - 50421, - 50404, - 50422, - 50423 - ], - "gidc": "Fd", - "nfid": 23 - }, - "파생잔고": { - "desc": "파생잔고", - "fids": [ - 9201, - 9001, - 302, - 10, - 930, - 931, - 932, - 933, - 945, - 946, - 950, - 951, - 27, - 28, - 307, - 8019, - 397, - 305, - 306, - 947 - ], - "gidc": "01", - "nfid": 20 - }, - "프로그램매매": { - "desc": "프로그램매매", - "fids": [ - 20, - 202, - 204, - 206, - 208, - 210, - 212, - 211, - 213, - 500, - 501, - 502, - 503, - 504, - 505, - 506, - 507, - 508, - 509, - 510, - 511, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520, - 521, - 522, - 523, - 524, - 525, - 526, - 527, - 528, - 529, - 530, - 531, - 532, - 533, - 534, - 535, - 536, - 537, - 538, - 539, - 540, - 541, - 542, - 543, - 544, - 545, - 546, - 547, - 548, - 549, - 550, - 551, - 197, - 183, - 195, - 928, - 929 - ], - "gidc": "0t", - "nfid": 66 - }, - "해외리얼잔고": { - "desc": "해외리얼잔고", - "fids": [ - 9201, - 9001, - 917, - 916, - 302, - 13000, - 13001, - 930, - 931, - 8002, - 10, - 8008, - 945, - 13004, - 13005, - 13006, - 13007, - 950, - 946, - 951, - 27, - 28, - 933, - 307, - 8019, - 957, - 958, - 918, - 990, - 991, - 992, - 993, - 13049, - 13050, - 13037, - 13054, - 13081, - 13090, - 13091, - 306, - 305, - 13092, - 959, - 13093, - 8046, - 8043, - 8045 - ], - "gidc": "0^", - "nfid": 47 - }, - "해외시세": { - "desc": "해외시세", - "fids": [ - 20, - 10, - 11, - 12, - 13, - 16, - 17, - 18, - 25, - 22 - ], - "gidc": "0R", - "nfid": 10 - }, - "해외실시간잔고조회": { - "desc": "해외실시간잔고조회", - "fids": [ - 9201, - 9064 - ], - "gidc": "FH", - "nfid": 2 - }, - "해외잔고": { - "desc": "해외잔고", - "fids": [ - 9201, - 9001, - 917, - 916, - 302, - 10, - 930, - 931, - 932, - 933, - 945, - 946, - 950, - 951, - 27, - 28, - 307, - 8019, - 957, - 958, - 918, - 990, - 991, - 992, - 993, - 959, - 8046, - 8043, - 8045 - ], - "gidc": "07", - "nfid": 29 - }, - "해외잔고총합": { - "desc": "해외잔고총합", - "fids": [ - 9201, - 13002, - 13003, - 13008, - 13009, - 950, - 13047, - 13048, - 13051, - 13052, - 13053, - 8019, - 990, - 991, - 992, - 993, - 13082, - 13083, - 13084, - 13085, - 13086, - 13087, - 13088, - 13089 - ], - "gidc": "0|", - "nfid": 24 - }, - "해외주문체결": { - "desc": "해외주문체결", - "fids": [ - 9201, - 9203, - 9205, - 9001, - 912, - 913, - 302, - 900, - 901, - 902, - 903, - 904, - 905, - 906, - 907, - 908, - 909, - 910, - 911, - 10, - 27, - 28, - 914, - 915, - 938, - 939, - 8046, - 8043, - 8000, - 985 - ], - "gidc": "0_", - "nfid": 30 - }, - "해외주식주문": { - "desc": "해외주식주문", - "fids": [ - 9201, - 9203, - 9001, - 905, - 8046, - 907, - 904, - 900, - 901, - 906, - 913, - 908, - 13320, - 50810, - 50716, - 8043, - 50841, - 55190, - 1091, - 50072, - 302, - 50073 - ], - "gidc": "F4", - "nfid": 22 - }, - "해외주식체결": { - "desc": "해외주식체결", - "fids": [ - 9201, - 9203, - 9001, - 905, - 8046, - 907, - 9210, - 904, - 909, - 900, - 901, - 911, - 910, - 13323, - 13324, - 13325, - 13326, - 913, - 902, - 908, - 13320, - 8018, - 8019, - 8004, - 8005, - 934, - 936, - 50842, - 50843, - 50726, - 50810, - 930, - 50708, - 931, - 50716, - 8043, - 50841, - 50844, - 55190, - 1091, - 13006, - 8075, - 50071, - 50072, - 302, - 50073, - 50724, - 50725 - ], - "gidc": "F5", - "nfid": 48 - }, - "현물잔고": { - "desc": "현물잔고", - "fids": [ - 9201, - 9001, - 917, - 916, - 302, - 10, - 930, - 931, - 932, - 933, - 945, - 946, - 950, - 951, - 27, - 28, - 307, - 8019, - 957, - 958, - 918, - 990, - 991, - 992, - 993, - 959, - 924, - 10010, - 25, - 11, - 12, - 306, - 305, - 970 - ], - "gidc": "04", - "nfid": 34 - }, - "홍콩단일가시세": { - "desc": "홍콩단일가시세", - "fids": [ - 20, - 291, - 292, - 294, - 295, - 293 - ], - "gidc": "1x", - "nfid": 6 - }, - "홍콩시세": { - "desc": "홍콩시세", - "fids": [ - 10, - 11, - 12, - 27, - 28, - 13, - 14, - 16, - 17, - 18, - 25, - 26, - 29, - 30, - 311, - 412, - 413 - ], - "gidc": "1M", - "nfid": 17 - }, - "홍콩실시간상하한가": { - "desc": "홍콩실시간상하한가", - "fids": [ - 305, - 306 - ], - "gidc": "1V", - "nfid": 2 - }, - "홍콩업종지수": { - "desc": "홍콩업종지수", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 14, - 16, - 17, - 18, - 25, - 26 - ], - "gidc": "1J", - "nfid": 12 - }, - "홍콩체결": { - "desc": "홍콩체결", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 25, - 197, - 26, - 246, - 247, - 248, - 30, - 196, - 845, - 848, - 846, - 849, - 847, - 850, - 851 - ], - "gidc": "1K", - "nfid": 34 - }, - "홍콩호가잔량": { - "desc": "홍콩호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 46, - 66, - 86, - 106, - 56, - 76, - 96, - 116, - 47, - 67, - 87, - 107, - 57, - 77, - 97, - 117, - 48, - 68, - 88, - 108, - 58, - 78, - 98, - 118, - 49, - 69, - 89, - 109, - 59, - 79, - 99, - 119, - 50, - 70, - 90, - 110, - 60, - 80, - 100, - 120, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "1N", - "nfid": 99 - }, - "환률": { - "desc": "환률", - "fids": [ - 570, - 571, - 572, - 573, - 574, - 575, - 576, - 577, - 578, - 579, - 580, - 581, - 582, - 583, - 584 - ], - "gidc": "0S", - "nfid": 15 - }, - "후강퉁단일가시세": { - "desc": "후강퉁단일가시세", - "fids": [ - 20, - 291, - 292, - 294, - 295, - 293 - ], - "gidc": "2x", - "nfid": 6 - }, - "후강퉁시세": { - "desc": "후강퉁시세", - "fids": [ - 10, - 11, - 12, - 27, - 28, - 13, - 14, - 16, - 17, - 18, - 25, - 26, - 29, - 30, - 311, - 412, - 413 - ], - "gidc": "2M", - "nfid": 17 - }, - "후강퉁업종지수": { - "desc": "후강퉁업종지수", - "fids": [ - 20, - 10, - 11, - 12, - 15, - 13, - 14, - 16, - 17, - 18, - 25, - 26 - ], - "gidc": "2J", - "nfid": 12 - }, - "후강퉁체결": { - "desc": "후강퉁체결", - "fids": [ - 20, - 10, - 11, - 12, - 27, - 28, - 15, - 13, - 14, - 16, - 17, - 18, - 195, - 182, - 184, - 183, - 186, - 181, - 185, - 25, - 197, - 26, - 246, - 247, - 248, - 30, - 196, - 845, - 848, - 846, - 849, - 847, - 850, - 851 - ], - "gidc": "2K", - "nfid": 34 - }, - "후강퉁호가잔량": { - "desc": "후강퉁호가잔량", - "fids": [ - 21, - 27, - 28, - 41, - 61, - 81, - 101, - 51, - 71, - 91, - 111, - 42, - 62, - 82, - 102, - 52, - 72, - 92, - 112, - 43, - 63, - 83, - 103, - 53, - 73, - 93, - 113, - 44, - 64, - 84, - 104, - 54, - 74, - 94, - 114, - 45, - 65, - 85, - 105, - 55, - 75, - 95, - 115, - 46, - 66, - 86, - 106, - 56, - 76, - 96, - 116, - 47, - 67, - 87, - 107, - 57, - 77, - 97, - 117, - 48, - 68, - 88, - 108, - 58, - 78, - 98, - 118, - 49, - 69, - 89, - 109, - 59, - 79, - 99, - 119, - 50, - 70, - 90, - 110, - 60, - 80, - 100, - 120, - 121, - 122, - 123, - 125, - 126, - 127, - 137, - 128, - 23, - 238, - 200, - 201, - 291, - 293, - 294, - 295 - ], - "gidc": "2N", - "nfid": 99 - } -} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/metadata/trinfo_by_code.json b/koapy/backend/kiwoom_open_api_plus/data/metadata/trinfo_by_code.json deleted file mode 100644 index d97951f6..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/metadata/trinfo_by_code.json +++ /dev/null @@ -1,35094 +0,0 @@ -{ - "opt10001": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식기본정보요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 389, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 50, - "start": 20 - }, - { - "fid": 315, - "name": "결산월", - "offset": 20, - "start": 40 - }, - { - "fid": 310, - "name": "액면가", - "offset": 20, - "start": 60 - }, - { - "fid": 309, - "name": "자본금", - "offset": 20, - "start": 80 - }, - { - "fid": 312, - "name": "상장주식", - "offset": 20, - "start": 100 - }, - { - "fid": 329, - "name": "신용비율", - "offset": 20, - "start": 120 - }, - { - "fid": 1006, - "name": "연중최고", - "offset": 20, - "start": 140 - }, - { - "fid": 1009, - "name": "연중최저", - "offset": 20, - "start": 160 - }, - { - "fid": 311, - "name": "시가총액", - "offset": 20, - "start": 180 - }, - { - "fid": 336, - "name": "시가총액비중", - "offset": 20, - "start": 200 - }, - { - "fid": 314, - "name": "외인소진률", - "offset": 20, - "start": 220 - }, - { - "fid": 308, - "name": "대용가", - "offset": 20, - "start": 240 - }, - { - "fid": 1600, - "name": "PER", - "offset": 20, - "start": 260 - }, - { - "fid": 1604, - "name": "EPS", - "offset": 20, - "start": 280 - }, - { - "fid": 1630, - "name": "ROE", - "offset": 20, - "start": 300 - }, - { - "fid": 1601, - "name": "PBR", - "offset": 20, - "start": 320 - }, - { - "fid": 1608, - "name": "EV", - "offset": 20, - "start": 340 - }, - { - "fid": 1605, - "name": "BPS", - "offset": 20, - "start": 360 - }, - { - "fid": 1610, - "name": "매출액", - "offset": 20, - "start": 380 - }, - { - "fid": 1611, - "name": "영업이익", - "offset": 20, - "start": 400 - }, - { - "fid": 1614, - "name": "당기순이익", - "offset": 20, - "start": 420 - }, - { - "fid": 1000, - "name": "250최고", - "offset": 20, - "start": 440 - }, - { - "fid": 1003, - "name": "250최저", - "offset": 20, - "start": 460 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 480 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 500 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 520 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 540 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 560 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 580 - }, - { - "fid": 10023, - "name": "예상체결가", - "offset": 20, - "start": 600 - }, - { - "fid": 10024, - "name": "예상체결수량", - "offset": 20, - "start": 620 - }, - { - "fid": 1001, - "name": "250최고가일", - "offset": 20, - "start": 640 - }, - { - "fid": 1002, - "name": "250최고가대비율", - "offset": 20, - "start": 660 - }, - { - "fid": 1004, - "name": "250최저가일", - "offset": 20, - "start": 680 - }, - { - "fid": 1005, - "name": "250최저가대비율", - "offset": 20, - "start": 700 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 720 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 740 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 760 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 780 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 800 - }, - { - "fid": 30, - "name": "거래대비", - "offset": 20, - "start": 820 - }, - { - "fid": 796, - "name": "액면가단위", - "offset": 20, - "start": 840 - }, - { - "fid": 1683, - "name": "유통주식", - "offset": 20, - "start": 840 - }, - { - "fid": 1684, - "name": "유통비율", - "offset": 20, - "start": 840 - } - ], - "single_outputs_name": "주식기본정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10001", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10002": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식거래원요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 120, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "등락부호", - "offset": 20, - "start": 160 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 180 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 200 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 220 - }, - { - "fid": 141, - "name": "매도거래원명1", - "offset": 20, - "start": 240 - }, - { - "fid": 146, - "name": "매도거래원1", - "offset": 20, - "start": 260 - }, - { - "fid": 161, - "name": "매도거래량1", - "offset": 20, - "start": 280 - }, - { - "fid": 151, - "name": "매수거래원명1", - "offset": 20, - "start": 300 - }, - { - "fid": 156, - "name": "매수거래원1", - "offset": 20, - "start": 320 - }, - { - "fid": 171, - "name": "매수거래량1", - "offset": 20, - "start": 340 - }, - { - "fid": 142, - "name": "매도거래원명2", - "offset": 20, - "start": 360 - }, - { - "fid": 147, - "name": "매도거래원2", - "offset": 20, - "start": 380 - }, - { - "fid": 162, - "name": "매도거래량2", - "offset": 20, - "start": 400 - }, - { - "fid": 152, - "name": "매수거래원명2", - "offset": 20, - "start": 420 - }, - { - "fid": 157, - "name": "매수거래원2", - "offset": 20, - "start": 440 - }, - { - "fid": 172, - "name": "매수거래량2", - "offset": 20, - "start": 460 - }, - { - "fid": 143, - "name": "매도거래원명3", - "offset": 20, - "start": 480 - }, - { - "fid": 148, - "name": "매도거래원3", - "offset": 20, - "start": 500 - }, - { - "fid": 163, - "name": "매도거래량3", - "offset": 20, - "start": 520 - }, - { - "fid": 153, - "name": "매수거래원명3", - "offset": 20, - "start": 540 - }, - { - "fid": 158, - "name": "매수거래원3", - "offset": 20, - "start": 560 - }, - { - "fid": 173, - "name": "매수거래량3", - "offset": 20, - "start": 580 - }, - { - "fid": 144, - "name": "매도거래원명4", - "offset": 20, - "start": 600 - }, - { - "fid": 149, - "name": "매도거래원4", - "offset": 20, - "start": 620 - }, - { - "fid": 164, - "name": "매도거래량4", - "offset": 20, - "start": 640 - }, - { - "fid": 154, - "name": "매수거래원명4", - "offset": 20, - "start": 660 - }, - { - "fid": 159, - "name": "매수거래원4", - "offset": 20, - "start": 680 - }, - { - "fid": 174, - "name": "매수거래량4", - "offset": 20, - "start": 700 - }, - { - "fid": 145, - "name": "매도거래원명5", - "offset": 20, - "start": 720 - }, - { - "fid": 150, - "name": "매도거래원5", - "offset": 20, - "start": 740 - }, - { - "fid": 165, - "name": "매도거래량5", - "offset": 20, - "start": 760 - }, - { - "fid": 155, - "name": "매수거래원명5", - "offset": 20, - "start": 780 - }, - { - "fid": 160, - "name": "매수거래원5", - "offset": 20, - "start": 800 - }, - { - "fid": 175, - "name": "매수거래량5", - "offset": 20, - "start": 820 - } - ], - "multi_outputs_name": "주식거래원", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10002", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10003": { - "gfid": "1500", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "체결정보요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 60 - }, - { - "fid": 27, - "name": "우선매도호가단위", - "offset": 20, - "start": 80 - }, - { - "fid": 28, - "name": "우선매수호가단위", - "offset": 20, - "start": 100 - }, - { - "fid": 15, - "name": "체결거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "sign", - "offset": 20, - "start": 140 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 160 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 180 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "체결정보", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "30", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10003", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10004": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식호가요청", - "multi_outputs": [ - { - "fid": 21, - "name": "호가잔량기준시간", - "offset": 20, - "start": 0 - }, - { - "fid": 90, - "name": "매도10차선잔량대비", - "offset": 20, - "start": 20 - }, - { - "fid": 70, - "name": "매도10차선잔량", - "offset": 20, - "start": 40 - }, - { - "fid": 50, - "name": "매도10차선호가", - "offset": 20, - "start": 60 - }, - { - "fid": 89, - "name": "매도9차선잔량대비", - "offset": 20, - "start": 80 - }, - { - "fid": 69, - "name": "매도9차선잔량", - "offset": 20, - "start": 100 - }, - { - "fid": 49, - "name": "매도9차선호가", - "offset": 20, - "start": 120 - }, - { - "fid": 88, - "name": "매도8차선잔량대비", - "offset": 20, - "start": 140 - }, - { - "fid": 68, - "name": "매도8차선잔량", - "offset": 20, - "start": 160 - }, - { - "fid": 48, - "name": "매도8차선호가", - "offset": 20, - "start": 180 - }, - { - "fid": 87, - "name": "매도7차선잔량대비", - "offset": 20, - "start": 200 - }, - { - "fid": 67, - "name": "매도7차선잔량", - "offset": 20, - "start": 220 - }, - { - "fid": 47, - "name": "매도7차선호가", - "offset": 20, - "start": 240 - }, - { - "fid": 86, - "name": "매도6차선잔량대비", - "offset": 20, - "start": 260 - }, - { - "fid": 66, - "name": "매도6우선잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 46, - "name": "매도6차선호가", - "offset": 20, - "start": 300 - }, - { - "fid": 85, - "name": "매도5차선잔량대비", - "offset": 20, - "start": 320 - }, - { - "fid": 65, - "name": "매도5차선잔량", - "offset": 20, - "start": 340 - }, - { - "fid": 45, - "name": "매도5차선호가", - "offset": 20, - "start": 360 - }, - { - "fid": 84, - "name": "매도4차선잔량대비", - "offset": 20, - "start": 380 - }, - { - "fid": 64, - "name": "매도4차선잔량", - "offset": 20, - "start": 400 - }, - { - "fid": 44, - "name": "매도4차선호가", - "offset": 20, - "start": 420 - }, - { - "fid": 83, - "name": "매도3차선잔량대비", - "offset": 20, - "start": 440 - }, - { - "fid": 63, - "name": "매도3차선잔량", - "offset": 20, - "start": 460 - }, - { - "fid": 43, - "name": "매도3차선호가", - "offset": 20, - "start": 480 - }, - { - "fid": 82, - "name": "매도2차선잔량대비", - "offset": 20, - "start": 500 - }, - { - "fid": 62, - "name": "매도2차선잔량", - "offset": 20, - "start": 520 - }, - { - "fid": 42, - "name": "매도2차선호가", - "offset": 20, - "start": 540 - }, - { - "fid": 81, - "name": "매도1차선잔량대비", - "offset": 20, - "start": 560 - }, - { - "fid": 61, - "name": "매도최우선잔량", - "offset": 20, - "start": 580 - }, - { - "fid": 41, - "name": "매도최우선호가", - "offset": 20, - "start": 600 - }, - { - "fid": 51, - "name": "매수최우선호가", - "offset": 20, - "start": 620 - }, - { - "fid": 71, - "name": "매수최우선잔량", - "offset": 20, - "start": 640 - }, - { - "fid": 91, - "name": "매수1차선잔량대비", - "offset": 20, - "start": 660 - }, - { - "fid": 52, - "name": "매수2차선호가", - "offset": 20, - "start": 680 - }, - { - "fid": 72, - "name": "매수2차선잔량", - "offset": 20, - "start": 700 - }, - { - "fid": 92, - "name": "매수2차선잔량대비", - "offset": 20, - "start": 720 - }, - { - "fid": 53, - "name": "매수3차선호가", - "offset": 20, - "start": 740 - }, - { - "fid": 73, - "name": "매수3차선잔량", - "offset": 20, - "start": 760 - }, - { - "fid": 93, - "name": "매수3차선잔량대비", - "offset": 20, - "start": 780 - }, - { - "fid": 54, - "name": "매수4차선호가", - "offset": 20, - "start": 800 - }, - { - "fid": 74, - "name": "매수4차선잔량", - "offset": 20, - "start": 820 - }, - { - "fid": 94, - "name": "매수4차선잔량대비", - "offset": 20, - "start": 840 - }, - { - "fid": 55, - "name": "매수5차선호가", - "offset": 20, - "start": 860 - }, - { - "fid": 75, - "name": "매수5차선잔량", - "offset": 20, - "start": 880 - }, - { - "fid": 95, - "name": "매수5차선잔량대비", - "offset": 20, - "start": 900 - }, - { - "fid": 56, - "name": "매수6우선호가", - "offset": 20, - "start": 920 - }, - { - "fid": 76, - "name": "매수6우선잔량", - "offset": 20, - "start": 940 - }, - { - "fid": 96, - "name": "매수6차선잔량대비", - "offset": 20, - "start": 960 - }, - { - "fid": 57, - "name": "매수7차선호가", - "offset": 20, - "start": 980 - }, - { - "fid": 77, - "name": "매수7차선잔량", - "offset": 20, - "start": 1000 - }, - { - "fid": 97, - "name": "매수7차선잔량대비", - "offset": 20, - "start": 1020 - }, - { - "fid": 58, - "name": "매수8차선호가", - "offset": 20, - "start": 1040 - }, - { - "fid": 78, - "name": "매수8차선잔량", - "offset": 20, - "start": 1060 - }, - { - "fid": 98, - "name": "매수8차선잔량대비", - "offset": 20, - "start": 1080 - }, - { - "fid": 59, - "name": "매수9차선호가", - "offset": 20, - "start": 1100 - }, - { - "fid": 79, - "name": "매수9차선잔량", - "offset": 20, - "start": 1120 - }, - { - "fid": 99, - "name": "매수9차선잔량대비", - "offset": 20, - "start": 1140 - }, - { - "fid": 60, - "name": "매수10차선호가", - "offset": 20, - "start": 1160 - }, - { - "fid": 80, - "name": "매수10차선잔량", - "offset": 20, - "start": 1180 - }, - { - "fid": 100, - "name": "매수10차선잔량대비", - "offset": 20, - "start": 1200 - }, - { - "fid": 122, - "name": "총매도잔량직전대비", - "offset": 20, - "start": 1220 - }, - { - "fid": 121, - "name": "총매도잔량", - "offset": 20, - "start": 1240 - }, - { - "fid": 125, - "name": "총매수잔량", - "offset": 20, - "start": 1260 - }, - { - "fid": 126, - "name": "총매수잔량직전대비", - "offset": 20, - "start": 1280 - }, - { - "fid": 132, - "name": "시간외매도잔량대비", - "offset": 20, - "start": 1300 - }, - { - "fid": 131, - "name": "시간외매도잔량", - "offset": 20, - "start": 1320 - }, - { - "fid": 135, - "name": "시간외매수잔량", - "offset": 20, - "start": 1340 - }, - { - "fid": 136, - "name": "시간외매수잔량대비", - "offset": 20, - "start": 1360 - } - ], - "multi_outputs_name": "주식호가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10004", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10005": { - "gfid": "1505", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식일주월시분요청", - "multi_outputs": [ - { - "fid": 22, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 20 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 40 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 80 - }, - { - "fid": 11, - "name": "대비", - "offset": 20, - "start": 100 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 120 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 140 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 160 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 180 - }, - { - "fid": 1066, - "name": "외인보유", - "offset": 20, - "start": 200 - }, - { - "fid": 1066, - "name": "외인비중", - "offset": 20, - "start": 220 - }, - { - "fid": 1137, - "name": "외인순매수", - "offset": 20, - "start": 240 - }, - { - "fid": 1136, - "name": "기관순매수", - "offset": 20, - "start": 260 - }, - { - "fid": 1140, - "name": "개인순매수", - "offset": 20, - "start": 280 - }, - { - "fid": 1188, - "name": "외국계", - "offset": 20, - "start": 300 - }, - { - "fid": 326, - "name": "신용잔고율", - "offset": 20, - "start": 320 - }, - { - "fid": 1189, - "name": "프로그램", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "주식일주월시분", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10005", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10006": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식시분요청", - "multi_outputs": [ - { - "fid": 22, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 20 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 40 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 80 - }, - { - "fid": 11, - "name": "대비", - "offset": 20, - "start": 100 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 120 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 140 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 160 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "주식시분", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10006", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10007": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "시세표성정보요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 40, - "start": 0 - }, - { - "fid": 389, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "날짜", - "offset": 20, - "start": 40 - }, - { - "fid": 21, - "name": "시간", - "offset": 20, - "start": 60 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 80 - }, - { - "fid": 304, - "name": "전일거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 120 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 140 - }, - { - "fid": 396, - "name": "전일거래대금", - "offset": 20, - "start": 160 - }, - { - "fid": 312, - "name": "상장주식수", - "offset": 20, - "start": 180 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 200 - }, - { - "fid": 25, - "name": "부호", - "offset": 20, - "start": 220 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 240 - }, - { - "fid": 30, - "name": "전일비", - "offset": 20, - "start": 260 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 280 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 300 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 320 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 340 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 360 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 380 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 400 - }, - { - "fid": 24, - "name": "예상체결량", - "offset": 20, - "start": 420 - }, - { - "fid": 27, - "name": "예상매도우선호가", - "offset": 20, - "start": 440 - }, - { - "fid": 28, - "name": "예상매수우선호가", - "offset": 20, - "start": 460 - }, - { - "fid": 439, - "name": "거래시작일", - "offset": 20, - "start": 480 - }, - { - "fid": 324, - "name": "행사가격", - "offset": 20, - "start": 500 - }, - { - "fid": 1018, - "name": "최고가", - "offset": 20, - "start": 520 - }, - { - "fid": 1021, - "name": "최저가", - "offset": 20, - "start": 540 - }, - { - "fid": 1019, - "name": "최고가일", - "offset": 20, - "start": 560 - }, - { - "fid": 1022, - "name": "최저가일", - "offset": 20, - "start": 580 - }, - { - "fid": 41, - "name": "매도1호가", - "offset": 20, - "start": 600 - }, - { - "fid": 42, - "name": "매도2호가", - "offset": 20, - "start": 620 - }, - { - "fid": 43, - "name": "매도3호가", - "offset": 20, - "start": 640 - }, - { - "fid": 44, - "name": "매도4호가", - "offset": 20, - "start": 660 - }, - { - "fid": 45, - "name": "매도5호가", - "offset": 20, - "start": 680 - }, - { - "fid": 46, - "name": "매도6호가", - "offset": 20, - "start": 700 - }, - { - "fid": 47, - "name": "매도7호가", - "offset": 20, - "start": 720 - }, - { - "fid": 48, - "name": "매도8호가", - "offset": 20, - "start": 740 - }, - { - "fid": 49, - "name": "매도9호가", - "offset": 20, - "start": 760 - }, - { - "fid": 50, - "name": "매도10호가", - "offset": 20, - "start": 780 - }, - { - "fid": 51, - "name": "매수1호가", - "offset": 20, - "start": 800 - }, - { - "fid": 52, - "name": "매수2호가", - "offset": 20, - "start": 820 - }, - { - "fid": 53, - "name": "매수3호가", - "offset": 20, - "start": 840 - }, - { - "fid": 54, - "name": "매수4호가", - "offset": 20, - "start": 860 - }, - { - "fid": 55, - "name": "매수5호가", - "offset": 20, - "start": 880 - }, - { - "fid": 56, - "name": "매수6호가", - "offset": 20, - "start": 900 - }, - { - "fid": 57, - "name": "매수7호가", - "offset": 20, - "start": 920 - }, - { - "fid": 58, - "name": "매수8호가", - "offset": 20, - "start": 940 - }, - { - "fid": 59, - "name": "매수9호가", - "offset": 20, - "start": 960 - }, - { - "fid": 60, - "name": "매수10호가", - "offset": 20, - "start": 980 - }, - { - "fid": 61, - "name": "매도1호가잔량", - "offset": 20, - "start": 1000 - }, - { - "fid": 62, - "name": "매도2호가잔량", - "offset": 20, - "start": 1020 - }, - { - "fid": 63, - "name": "매도3호가잔량", - "offset": 20, - "start": 1040 - }, - { - "fid": 64, - "name": "매도4호가잔량", - "offset": 20, - "start": 1060 - }, - { - "fid": 65, - "name": "매도5호가잔량", - "offset": 20, - "start": 1080 - }, - { - "fid": 66, - "name": "매도6호가잔량", - "offset": 20, - "start": 1100 - }, - { - "fid": 67, - "name": "매도7호가잔량", - "offset": 20, - "start": 1120 - }, - { - "fid": 68, - "name": "매도8호가잔량", - "offset": 20, - "start": 1140 - }, - { - "fid": 69, - "name": "매도9호가잔량", - "offset": 20, - "start": 1160 - }, - { - "fid": 70, - "name": "매도10호가잔량", - "offset": 20, - "start": 1180 - }, - { - "fid": 71, - "name": "매수1호가잔량", - "offset": 20, - "start": 1200 - }, - { - "fid": 72, - "name": "매수2호가잔량", - "offset": 20, - "start": 1220 - }, - { - "fid": 73, - "name": "매수3호가잔량", - "offset": 20, - "start": 1240 - }, - { - "fid": 74, - "name": "매수4호가잔량", - "offset": 20, - "start": 1260 - }, - { - "fid": 75, - "name": "매수5호가잔량", - "offset": 20, - "start": 1280 - }, - { - "fid": 76, - "name": "매수6호가잔량", - "offset": 20, - "start": 1300 - }, - { - "fid": 77, - "name": "매수7호가잔량", - "offset": 20, - "start": 1320 - }, - { - "fid": 78, - "name": "매수8호가잔량", - "offset": 20, - "start": 1340 - }, - { - "fid": 79, - "name": "매수9호가잔량", - "offset": 20, - "start": 1360 - }, - { - "fid": 80, - "name": "매수10호가잔량", - "offset": 20, - "start": 1380 - }, - { - "fid": 81, - "name": "매도1호가직전대비", - "offset": 20, - "start": 1400 - }, - { - "fid": 82, - "name": "매도2호가직전대비", - "offset": 20, - "start": 1420 - }, - { - "fid": 83, - "name": "매도3호가직전대비", - "offset": 20, - "start": 1440 - }, - { - "fid": 84, - "name": "매도4호가직전대비", - "offset": 20, - "start": 1460 - }, - { - "fid": 85, - "name": "매도5호가직전대비", - "offset": 20, - "start": 1480 - }, - { - "fid": 86, - "name": "매도6호가직전대비", - "offset": 20, - "start": 1500 - }, - { - "fid": 87, - "name": "매도7호가직전대비", - "offset": 20, - "start": 1520 - }, - { - "fid": 88, - "name": "매도8호가직전대비", - "offset": 20, - "start": 1540 - }, - { - "fid": 89, - "name": "매도9호가직전대비", - "offset": 20, - "start": 1560 - }, - { - "fid": 90, - "name": "매도10호가직전대비", - "offset": 20, - "start": 1580 - }, - { - "fid": 91, - "name": "매수1호가직전대비", - "offset": 20, - "start": 1600 - }, - { - "fid": 92, - "name": "매수2호가직전대비", - "offset": 20, - "start": 1620 - }, - { - "fid": 93, - "name": "매수3호가직전대비", - "offset": 20, - "start": 1640 - }, - { - "fid": 94, - "name": "매수4호가직전대비", - "offset": 20, - "start": 1660 - }, - { - "fid": 95, - "name": "매수5호가직전대비", - "offset": 20, - "start": 1680 - }, - { - "fid": 96, - "name": "매수6호가직전대비", - "offset": 20, - "start": 1700 - }, - { - "fid": 97, - "name": "매수7호가직전대비", - "offset": 20, - "start": 1720 - }, - { - "fid": 98, - "name": "매수8호가직전대비", - "offset": 20, - "start": 1740 - }, - { - "fid": 99, - "name": "매수9호가직전대비", - "offset": 20, - "start": 1760 - }, - { - "fid": 100, - "name": "매수10호가직전대비", - "offset": 20, - "start": 1780 - }, - { - "fid": 101, - "name": "매도1호가건수", - "offset": 20, - "start": 1800 - }, - { - "fid": 102, - "name": "매도2호가건수", - "offset": 20, - "start": 1820 - }, - { - "fid": 103, - "name": "매도3호가건수", - "offset": 20, - "start": 1840 - }, - { - "fid": 104, - "name": "매도4호가건수", - "offset": 20, - "start": 1860 - }, - { - "fid": 105, - "name": "매도5호가건수", - "offset": 20, - "start": 1880 - }, - { - "fid": 111, - "name": "매수1호가건수", - "offset": 20, - "start": 1900 - }, - { - "fid": 112, - "name": "매수2호가건수", - "offset": 20, - "start": 1920 - }, - { - "fid": 113, - "name": "매수3호가건수", - "offset": 20, - "start": 1940 - }, - { - "fid": 114, - "name": "매수4호가건수", - "offset": 20, - "start": 1960 - }, - { - "fid": 115, - "name": "매수5호가건수", - "offset": 20, - "start": 1980 - }, - { - "fid": 621, - "name": "LP매도1호가잔량", - "offset": 20, - "start": 2000 - }, - { - "fid": 622, - "name": "LP매도2호가잔량", - "offset": 20, - "start": 2020 - }, - { - "fid": 623, - "name": "LP매도3호가잔량", - "offset": 20, - "start": 2040 - }, - { - "fid": 624, - "name": "LP매도4호가잔량", - "offset": 20, - "start": 2060 - }, - { - "fid": 625, - "name": "LP매도5호가잔량", - "offset": 20, - "start": 2080 - }, - { - "fid": 626, - "name": "LP매도6호가잔량", - "offset": 20, - "start": 2100 - }, - { - "fid": 627, - "name": "LP매도7호가잔량", - "offset": 20, - "start": 2120 - }, - { - "fid": 628, - "name": "LP매도8호가잔량", - "offset": 20, - "start": 2140 - }, - { - "fid": 629, - "name": "LP매도9호가잔량", - "offset": 20, - "start": 2160 - }, - { - "fid": 630, - "name": "LP매도10호가잔량", - "offset": 20, - "start": 2180 - }, - { - "fid": 631, - "name": "LP매수1호가잔량", - "offset": 20, - "start": 2200 - }, - { - "fid": 632, - "name": "LP매수2호가잔량", - "offset": 20, - "start": 2220 - }, - { - "fid": 633, - "name": "LP매수3호가잔량", - "offset": 20, - "start": 2240 - }, - { - "fid": 634, - "name": "LP매수4호가잔량", - "offset": 20, - "start": 2260 - }, - { - "fid": 635, - "name": "LP매수5호가잔량", - "offset": 20, - "start": 2280 - }, - { - "fid": 636, - "name": "LP매수6호가잔량", - "offset": 20, - "start": 2300 - }, - { - "fid": 637, - "name": "LP매수7호가잔량", - "offset": 20, - "start": 2320 - }, - { - "fid": 638, - "name": "LP매수8호가잔량", - "offset": 20, - "start": 2340 - }, - { - "fid": 639, - "name": "LP매수9호가잔량", - "offset": 20, - "start": 2360 - }, - { - "fid": 640, - "name": "LP매수10호가잔량", - "offset": 20, - "start": 2380 - }, - { - "fid": 125, - "name": "총매수잔량", - "offset": 20, - "start": 2400 - }, - { - "fid": 121, - "name": "총매도잔량", - "offset": 20, - "start": 2420 - }, - { - "fid": 127, - "name": "총매수건수", - "offset": 20, - "start": 2440 - }, - { - "fid": 123, - "name": "총매도건수", - "offset": 20, - "start": 2460 - } - ], - "multi_outputs_name": "시세표성정보", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10007", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10008": { - "gfid": "2052", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식외국인요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 60 - }, - { - "fid": 210, - "name": "변동수량", - "offset": 20, - "start": 80 - }, - { - "fid": 313, - "name": "보유주식수", - "offset": 20, - "start": 100 - }, - { - "fid": 1066, - "name": "비중", - "offset": 20, - "start": 120 - }, - { - "fid": 344, - "name": "취득가능주식수", - "offset": 20, - "start": 140 - }, - { - "fid": 345, - "name": "외국인한도", - "offset": 20, - "start": 160 - }, - { - "fid": 399, - "name": "외국인한도증감", - "offset": 20, - "start": 180 - }, - { - "fid": 314, - "name": "한도소진률", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "주식외국인", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10008", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10009": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주식기관요청", - "multi_outputs": [ - { - "fid": 22, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "대비", - "offset": 20, - "start": 40 - }, - { - "fid": 1060, - "name": "기관기간누적", - "offset": 20, - "start": 60 - }, - { - "fid": 1140, - "name": "기관일변순매매", - "offset": 20, - "start": 80 - }, - { - "fid": 1145, - "name": "외국인일변순매매", - "offset": 20, - "start": 100 - }, - { - "fid": 1146, - "name": "외국인지분율", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "주식기관", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10009", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10010": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "업종프로그램요청", - "multi_outputs": [ - { - "fid": 500, - "name": "차익위탁매도수량", - "offset": 20, - "start": 0 - }, - { - "fid": 503, - "name": "차익위탁매도금액", - "offset": 20, - "start": 20 - }, - { - "fid": 509, - "name": "차익위탁매수수량", - "offset": 20, - "start": 40 - }, - { - "fid": 512, - "name": "차익위탁매수금액", - "offset": 20, - "start": 60 - }, - { - "fid": 520, - "name": "차익위탁순매수수량", - "offset": 20, - "start": 80 - }, - { - "fid": 518, - "name": "차익위탁순매수금액", - "offset": 20, - "start": 100 - }, - { - "fid": 524, - "name": "비차익위탁매도수량", - "offset": 20, - "start": 120 - }, - { - "fid": 527, - "name": "비차익위탁매도금액", - "offset": 20, - "start": 140 - }, - { - "fid": 533, - "name": "비차익위탁매수수량", - "offset": 20, - "start": 160 - }, - { - "fid": 536, - "name": "비차익위탁매수금액", - "offset": 20, - "start": 180 - }, - { - "fid": 544, - "name": "비차익위탁순매수수량", - "offset": 20, - "start": 200 - }, - { - "fid": 542, - "name": "비차익위탁순매수금액", - "offset": 20, - "start": 220 - }, - { - "fid": 202, - "name": "전체차익위탁매도수량", - "offset": 20, - "start": 240 - }, - { - "fid": 204, - "name": "전체차익위탁매도금액", - "offset": 20, - "start": 260 - }, - { - "fid": 206, - "name": "전체차익위탁매수수량", - "offset": 20, - "start": 280 - }, - { - "fid": 208, - "name": "전체차익위탁매수금액", - "offset": 20, - "start": 300 - }, - { - "fid": 210, - "name": "전체차익위탁순매수수량", - "offset": 20, - "start": 320 - }, - { - "fid": 212, - "name": "전체차익위탁순매수금액", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "업종프로그램", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10010", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10011": { - "gfid": "2025", - "inputs": [ - { - "fid": 9113, - "name": "신주인수권구분", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "신주인수권전체시세요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 40, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 60 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 80 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 100 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 120 - }, - { - "fid": 27, - "name": "최우선매도호가", - "offset": 20, - "start": 140 - }, - { - "fid": 28, - "name": "최우선매수호가", - "offset": 20, - "start": 160 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 180 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 200 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 220 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "신주인수권시세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "1000", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10011", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10012": { - "gfid": "", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "주문체결요청", - "multi_outputs": [ - { - "fid": 900, - "name": "주문수량", - "offset": 20, - "start": 0 - }, - { - "fid": 901, - "name": "주문가격", - "offset": 20, - "start": 20 - }, - { - "fid": 902, - "name": "미체결수량", - "offset": 20, - "start": 40 - }, - { - "fid": 903, - "name": "체결누계금액", - "offset": 20, - "start": 60 - }, - { - "fid": 904, - "name": "원주문번호", - "offset": 20, - "start": 80 - }, - { - "fid": 905, - "name": "주문구분", - "offset": 20, - "start": 100 - }, - { - "fid": 906, - "name": "매매구분", - "offset": 20, - "start": 120 - }, - { - "fid": 907, - "name": "매도수구분", - "offset": 20, - "start": 140 - }, - { - "fid": 908, - "name": "주문/체결시간", - "offset": 20, - "start": 160 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 180 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 200 - }, - { - "fid": 913, - "name": "주문상태", - "offset": 20, - "start": 220 - }, - { - "fid": 914, - "name": "단위체결가", - "offset": 20, - "start": 240 - }, - { - "fid": 916, - "name": "대출일", - "offset": 20, - "start": 260 - }, - { - "fid": 917, - "name": "신용구분", - "offset": 20, - "start": 280 - }, - { - "fid": 918, - "name": "만기일", - "offset": 20, - "start": 300 - }, - { - "fid": 930, - "name": "보유수량", - "offset": 20, - "start": 340 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 360 - }, - { - "fid": 932, - "name": "총매입가", - "offset": 20, - "start": 380 - }, - { - "fid": 933, - "name": "주문가능수량", - "offset": 20, - "start": 400 - }, - { - "fid": 934, - "name": "당일매도수량", - "offset": 20, - "start": 420 - }, - { - "fid": 935, - "name": "당일매도금액", - "offset": 20, - "start": 440 - }, - { - "fid": 936, - "name": "당일매수수량", - "offset": 20, - "start": 460 - }, - { - "fid": 937, - "name": "당일매수금액", - "offset": 20, - "start": 480 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 500 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 520 - }, - { - "fid": 940, - "name": "당일hts매도수수료", - "offset": 20, - "start": 540 - }, - { - "fid": 941, - "name": "당일hts매수수수료", - "offset": 20, - "start": 560 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 580 - }, - { - "fid": 945, - "name": "당일순매수량", - "offset": 20, - "start": 600 - }, - { - "fid": 946, - "name": "매도/매수구분", - "offset": 20, - "start": 620 - }, - { - "fid": 950, - "name": "당일총매도손일", - "offset": 20, - "start": 640 - }, - { - "fid": 951, - "name": "예수금", - "offset": 20, - "start": 660 - }, - { - "fid": 952, - "name": "사용가능현금", - "offset": 20, - "start": 680 - }, - { - "fid": 953, - "name": "사용가능대용", - "offset": 20, - "start": 700 - }, - { - "fid": 954, - "name": "전일재사용", - "offset": 20, - "start": 720 - }, - { - "fid": 955, - "name": "당일재사용", - "offset": 20, - "start": 740 - }, - { - "fid": 956, - "name": "담보현금", - "offset": 20, - "start": 760 - }, - { - "fid": 957, - "name": "신용금액", - "offset": 20, - "start": 780 - }, - { - "fid": 958, - "name": "신용이자", - "offset": 20, - "start": 800 - }, - { - "fid": 959, - "name": "담보대출수량", - "offset": 20, - "start": 820 - }, - { - "fid": 961, - "name": "현물주문체결이상유무", - "offset": 20, - "start": 840 - }, - { - "fid": 962, - "name": "현물잔고이상유무", - "offset": 20, - "start": 860 - }, - { - "fid": 963, - "name": "현물예수금이상유무", - "offset": 20, - "start": 880 - }, - { - "fid": 966, - "name": "선물주문체결이상유무", - "offset": 20, - "start": 900 - }, - { - "fid": 967, - "name": "선물잔고이상유무", - "offset": 20, - "start": 920 - }, - { - "fid": 971, - "name": "D+1추정예수금", - "offset": 20, - "start": 940 - }, - { - "fid": 972, - "name": "D+2추정예수금", - "offset": 20, - "start": 960 - }, - { - "fid": 973, - "name": "D+1매수/매도정산금", - "offset": 20, - "start": 980 - }, - { - "fid": 974, - "name": "D+2매수/매도정산금", - "offset": 20, - "start": 1000 - }, - { - "fid": 975, - "name": "D+1연체변제소요금", - "offset": 20, - "start": 1020 - }, - { - "fid": 976, - "name": "D+2연체변제소요금", - "offset": 20, - "start": 1040 - }, - { - "fid": 977, - "name": "D+1추정인출가능금", - "offset": 20, - "start": 1060 - }, - { - "fid": 978, - "name": "D+2추정인출가능금", - "offset": 20, - "start": 1080 - }, - { - "fid": 979, - "name": "현금증거금", - "offset": 20, - "start": 1100 - }, - { - "fid": 980, - "name": "대용잔고", - "offset": 20, - "start": 1120 - }, - { - "fid": 981, - "name": "대용증거금", - "offset": 20, - "start": 1140 - }, - { - "fid": 982, - "name": "수표금액", - "offset": 20, - "start": 1160 - }, - { - "fid": 983, - "name": "현금미수금", - "offset": 20, - "start": 1180 - }, - { - "fid": 984, - "name": "신용설정보증금", - "offset": 20, - "start": 1200 - }, - { - "fid": 985, - "name": "인출가능금액", - "offset": 20, - "start": 1220 - } - ], - "multi_outputs_name": "주문체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10012", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10013": { - "gfid": "2309", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9062, - "name": "조회구분", - "offset": 1, - "start": 14 - } - ], - "inputs_name": "신용매매동향요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 876, - "name": "신규", - "offset": 20, - "start": 120 - }, - { - "fid": 870, - "name": "상환", - "offset": 20, - "start": 140 - }, - { - "fid": 871, - "name": "잔고", - "offset": 20, - "start": 160 - }, - { - "fid": 872, - "name": "금액", - "offset": 20, - "start": 180 - }, - { - "fid": 873, - "name": "대비", - "offset": 20, - "start": 200 - }, - { - "fid": 874, - "name": "공여율", - "offset": 20, - "start": 220 - }, - { - "fid": 875, - "name": "잔고율", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "신용매매동향", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10013", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10014": { - "gfid": "2075", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9050, - "name": "시간구분", - "offset": 1, - "start": 6 - }, - { - "fid": 9005, - "name": "시작일자", - "offset": 8, - "start": 7 - }, - { - "fid": 9004, - "name": "종료일자", - "offset": 8, - "start": 15 - } - ], - "inputs_name": "공매도추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 19, - "name": "종가", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 80 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 100 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 554, - "name": "공매도량", - "offset": 20, - "start": 140 - }, - { - "fid": 556, - "name": "매매비중", - "offset": 20, - "start": 160 - }, - { - "fid": 555, - "name": "공매도거래대금", - "offset": 20, - "start": 180 - }, - { - "fid": 1142, - "name": "공매도평균가", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "공매도추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10014", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10015": { - "gfid": "2076", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 6 - } - ], - "inputs_name": "일별거래상세요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 80 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 140 - }, - { - "fid": 1402, - "name": "장전거래량", - "offset": 20, - "start": 160 - }, - { - "fid": 1410, - "name": "장전거래비중", - "offset": 20, - "start": 180 - }, - { - "fid": 1400, - "name": "장중거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 1408, - "name": "장중거래비중", - "offset": 20, - "start": 220 - }, - { - "fid": 1401, - "name": "장후거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 1409, - "name": "장후거래비중", - "offset": 20, - "start": 260 - }, - { - "fid": 13, - "name": "합계3", - "offset": 20, - "start": 280 - }, - { - "fid": 14, - "name": "기간중거래량", - "offset": 20, - "start": 300 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 180 - }, - { - "fid": 1066, - "name": "외인보유", - "offset": 20, - "start": 200 - }, - { - "fid": 1066, - "name": "외인비중", - "offset": 20, - "start": 220 - }, - { - "fid": 1137, - "name": "외인순매수", - "offset": 20, - "start": 240 - }, - { - "fid": 1136, - "name": "기관순매수", - "offset": 20, - "start": 260 - }, - { - "fid": 1140, - "name": "개인순매수", - "offset": 20, - "start": 280 - }, - { - "fid": 1138, - "name": "외국계", - "offset": 20, - "start": 300 - }, - { - "fid": 326, - "name": "신용잔고율", - "offset": 20, - "start": 320 - }, - { - "fid": 1139, - "name": "프로그램", - "offset": 20, - "start": 340 - }, - { - "fid": 1406, - "name": "장전거래대금", - "offset": 20, - "start": 160 - }, - { - "fid": 1413, - "name": "장전거래대금비중", - "offset": 20, - "start": 180 - }, - { - "fid": 1404, - "name": "장중거래대금", - "offset": 20, - "start": 200 - }, - { - "fid": 1411, - "name": "장중거래대금비중", - "offset": 20, - "start": 220 - }, - { - "fid": 1405, - "name": "장후거래대금", - "offset": 20, - "start": 240 - }, - { - "fid": 1412, - "name": "장후거래대금비중", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "일별거래상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10015", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10016": { - "gfid": "2004", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9011, - "name": "신고저구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9018, - "name": "고저종구분", - "offset": 1, - "start": 5 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 6 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 5, - "start": 7 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 12 - }, - { - "fid": 9076, - "name": "상하한포함", - "offset": 1, - "start": 13 - }, - { - "fid": 9012, - "name": "기간", - "offset": 3, - "start": 14 - } - ], - "inputs_name": "신고저가요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 30, - "name": "전일거래량대비율", - "offset": 20, - "start": 220 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 240 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 260 - }, - { - "fid": 1025, - "name": "고가", - "offset": 20, - "start": 280 - }, - { - "fid": 1026, - "name": "저가", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "신고저가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10016", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10017": { - "gfid": "2007", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9017, - "name": "상하한구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 5 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 5, - "start": 6 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9077, - "name": "매매금구분", - "offset": 1, - "start": 12 - } - ], - "inputs_name": "상하한가요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 300, - "name": "종목정보", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 304, - "name": "전일거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 61, - "name": "매도잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 280 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 300 - }, - { - "fid": 71, - "name": "매수잔량", - "offset": 20, - "start": 320 - }, - { - "fid": 333, - "name": "횟수", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "상하한가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10017", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10018": { - "gfid": "2008", - "inputs": [ - { - "fid": 9018, - "name": "고저구분", - "offset": 1, - "start": 0 - }, - { - "fid": 9019, - "name": "근접율", - "offset": 2, - "start": 1 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 5, - "start": 6 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 12 - } - ], - "inputs_name": "고저가근접요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 125, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 220 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 240 - }, - { - "fid": 17, - "name": "당일고가", - "offset": 20, - "start": 260 - }, - { - "fid": 18, - "name": "당일저가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "고저가근접", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10018", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10019": { - "gfid": "2009", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9020, - "name": "등락구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9021, - "name": "시간구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9013, - "name": "시간", - "offset": 2, - "start": 5 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 4, - "start": 7 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 12 - }, - { - "fid": 9077, - "name": "가격조건", - "offset": 1, - "start": 13 - }, - { - "fid": 9076, - "name": "상하한포함", - "offset": 1, - "start": 14 - } - ], - "inputs_name": "가격급등락요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 300, - "name": "종목분류", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 1027, - "name": "기준가", - "offset": 20, - "start": 200 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 220 - }, - { - "fid": 1028, - "name": "기준대비", - "offset": 20, - "start": 240 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 260 - }, - { - "fid": 1037, - "name": "급등률", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "가격급등락", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10019", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10020": { - "gfid": "2204", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 4, - "start": 4 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 8 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 9 - } - ], - "inputs_name": "호가잔량상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 180 - }, - { - "fid": 121, - "name": "총매도잔량", - "offset": 20, - "start": 200 - }, - { - "fid": 125, - "name": "총매수잔량", - "offset": 20, - "start": 220 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 240 - }, - { - "fid": 129, - "name": "매수비율", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "호가잔량상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10020", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10021": { - "gfid": "2010", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9024, - "name": "매매구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9013, - "name": "시간구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 4, - "start": 4 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 8 - } - ], - "inputs_name": "호가잔량급증요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 1034, - "name": "기준률", - "offset": 20, - "start": 180 - }, - { - "fid": 125, - "name": "현재", - "offset": 20, - "start": 200 - }, - { - "fid": 1036, - "name": "급증수량", - "offset": 20, - "start": 220 - }, - { - "fid": 1037, - "name": "급증률", - "offset": 20, - "start": 240 - }, - { - "fid": 206, - "name": "총매수량", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "호가잔량급증", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10021", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10022": { - "gfid": "2011", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9025, - "name": "비율구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9013, - "name": "시간구분", - "offset": 2, - "start": 4 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 1, - "start": 6 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 7 - } - ], - "inputs_name": "잔량율급증요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 1034, - "name": "기준률", - "offset": 20, - "start": 180 - }, - { - "fid": 1035, - "name": "현재비율", - "offset": 20, - "start": 200 - }, - { - "fid": 1037, - "name": "급증률", - "offset": 20, - "start": 220 - }, - { - "fid": 121, - "name": "총매도잔량", - "offset": 20, - "start": 240 - }, - { - "fid": 125, - "name": "총매수잔량", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "잔량율급증", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10022", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10023": { - "gfid": "2012", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9021, - "name": "시간구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 1, - "start": 5 - }, - { - "fid": 9013, - "name": "시간", - "offset": 2, - "start": 6 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 8 - }, - { - "fid": 9077, - "name": "가격구분", - "offset": 1, - "start": 9 - } - ], - "inputs_name": "거래량급증요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 1033, - "name": "이전거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 1036, - "name": "급증량", - "offset": 20, - "start": 240 - }, - { - "fid": 1037, - "name": "급증률", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "거래량급증", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10023", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10024": { - "gfid": "2013", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9012, - "name": "주기구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 1, - "start": 4 - } - ], - "inputs_name": "거래량갱신요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 1033, - "name": "이전거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 240 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "거래량갱신", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10024", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10025": { - "gfid": "2014", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9029, - "name": "매물집중비율", - "offset": 2, - "start": 3 - }, - { - "fid": 9030, - "name": "현재가진입", - "offset": 1, - "start": 5 - }, - { - "fid": 9045, - "name": "매물대수", - "offset": 1, - "start": 6 - }, - { - "fid": 9012, - "name": "주기구분", - "offset": 3, - "start": 7 - } - ], - "inputs_name": "매물대집중요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 1046, - "name": "가격대시작", - "offset": 20, - "start": 220 - }, - { - "fid": 1047, - "name": "가격대끝", - "offset": 20, - "start": 240 - }, - { - "fid": 1048, - "name": "매물량", - "offset": 20, - "start": 260 - }, - { - "fid": 1049, - "name": "매물비", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "매물대집중", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10025", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10026": { - "gfid": "2015", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 1, - "start": 0 - }, - { - "fid": 9047, - "name": "PER구분", - "offset": 1, - "start": 1 - } - ], - "inputs_name": "고저PER요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 20 - }, - { - "fid": 316, - "name": "PER", - "offset": 20, - "start": 160 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 180 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 200 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 240 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 260 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "고저PER", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10026", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10027": { - "gfid": "2208", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량조건", - "offset": 5, - "start": 4 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 2, - "start": 9 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9076, - "name": "상하한포함", - "offset": 2, - "start": 12 - }, - { - "fid": 9077, - "name": "가격조건", - "offset": 2, - "start": 14 - }, - { - "fid": 9080, - "name": "거래대금조건", - "offset": 4, - "start": 16 - } - ], - "inputs_name": "전일대비등락률상위요청", - "multi_outputs": [ - { - "fid": 300, - "name": "종목분류", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 180 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 200 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 240 - }, - { - "fid": 121, - "name": "매도잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 125, - "name": "매수잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 300 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 320 - }, - { - "fid": 333, - "name": "횟수", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "전일대비등락률상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10027", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10028": { - "gfid": "2209", - "inputs": [ - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 0 - }, - { - "fid": 9022, - "name": "거래량조건", - "offset": 4, - "start": 1 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 5 - }, - { - "fid": 9076, - "name": "상하한포함", - "offset": 1, - "start": 8 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 2, - "start": 9 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9080, - "name": "거래대금조건", - "offset": 4, - "start": 11 - }, - { - "fid": 9017, - "name": "등락조건", - "offset": 1, - "start": 15 - } - ], - "inputs_name": "시가대비등락률요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 160 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 180 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 200 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 220 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 240 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 260 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 280 - }, - { - "fid": 1040, - "name": "시가대비", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 320 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "시가대비등락률", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10028", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10029": { - "gfid": "2210", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9022, - "name": "거래량조건", - "offset": 5, - "start": 4 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 2, - "start": 9 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 11 - }, - { - "fid": 9077, - "name": "가격조건", - "offset": 2, - "start": 12 - } - ], - "inputs_name": "예상체결등락률상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 20 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 160 - }, - { - "fid": 346, - "name": "기준가", - "offset": 20, - "start": 180 - }, - { - "fid": 1067, - "name": "전일대비기호", - "offset": 20, - "start": 200 - }, - { - "fid": 1055, - "name": "전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 1056, - "name": "등락률", - "offset": 20, - "start": 240 - }, - { - "fid": 24, - "name": "예상체결량", - "offset": 20, - "start": 260 - }, - { - "fid": 61, - "name": "매도잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 300 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 320 - }, - { - "fid": 71, - "name": "매수잔량", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "예상체결등락률상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10029", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10030": { - "gfid": "2201", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9060, - "name": "관리종목포함", - "offset": 1, - "start": 4 - }, - { - "fid": 9062, - "name": "신용구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9077, - "name": "가격구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9080, - "name": "거래대금구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9114, - "name": "장운영구분", - "offset": 1, - "start": 4 - } - ], - "inputs_name": "당일거래량상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 30, - "name": "전일비", - "offset": 20, - "start": 220 - }, - { - "fid": 31, - "name": "거래회전율", - "offset": 20, - "start": 240 - }, - { - "fid": 14, - "name": "거래금액", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "당일거래량상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10030", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10031": { - "gfid": "2205", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9023, - "name": "조회구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9027, - "name": "순위시작", - "offset": 2, - "start": 4 - }, - { - "fid": 9028, - "name": "순위끝", - "offset": 2, - "start": 6 - } - ], - "inputs_name": "전일거래량상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "전일거래량상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10031", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10032": { - "gfid": "2206", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9010, - "name": "관리종목포함", - "offset": 1, - "start": 3 - } - ], - "inputs_name": "거래대금상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 401, - "name": "현재순위", - "offset": 20, - "start": 20 - }, - { - "fid": 410, - "name": "전일순위", - "offset": 20, - "start": 40 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 60 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 160 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 180 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 200 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 220 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 240 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 260 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 280 - }, - { - "fid": 304, - "name": "전일거래량", - "offset": 20, - "start": 300 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "거래대금상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10032", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10033": { - "gfid": "2213", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 3, - "start": 3 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 1, - "start": 6 - }, - { - "fid": 9076, - "name": "상하한포함", - "offset": 1, - "start": 7 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 1, - "start": 8 - } - ], - "inputs_name": "신용비율상위요청", - "multi_outputs": [ - { - "fid": 300, - "name": "종목정보", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 200 - }, - { - "fid": 329, - "name": "신용비율", - "offset": 20, - "start": 220 - }, - { - "fid": 121, - "name": "매도잔량", - "offset": 20, - "start": 240 - }, - { - "fid": 125, - "name": "매수잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "신용비율상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10033", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10034": { - "gfid": "2054", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9012, - "name": "기간", - "offset": 2, - "start": 4 - } - ], - "inputs_name": "외인기간별매매상위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 200 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 210, - "name": "순매수량", - "offset": 20, - "start": 260 - }, - { - "fid": 344, - "name": "취득가능주식수", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "외인기간별매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10034", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10035": { - "gfid": "2055", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9049, - "name": "기준일구분", - "offset": 1, - "start": 4 - } - ], - "inputs_name": "외인연속순매매상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 355, - "name": "D-1", - "offset": 20, - "start": 180 - }, - { - "fid": 356, - "name": "D-2", - "offset": 20, - "start": 200 - }, - { - "fid": 357, - "name": "D-3", - "offset": 20, - "start": 220 - }, - { - "fid": 358, - "name": "합계", - "offset": 20, - "start": 240 - }, - { - "fid": 314, - "name": "한도소진율", - "offset": 20, - "start": 260 - }, - { - "fid": 1041, - "name": "전일대비1", - "offset": 20, - "start": 280 - }, - { - "fid": 1042, - "name": "전일대비2", - "offset": 20, - "start": 300 - }, - { - "fid": 1043, - "name": "전일대비3", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "외인연속순매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10035", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10036": { - "gfid": "2056", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9012, - "name": "기간", - "offset": 2, - "start": 3 - } - ], - "inputs_name": "외인한도소진율증가상위", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 313, - "name": "보유주식수", - "offset": 20, - "start": 220 - }, - { - "fid": 344, - "name": "취득가능주식수", - "offset": 20, - "start": 240 - }, - { - "fid": 359, - "name": "기준한도소진율", - "offset": 20, - "start": 260 - }, - { - "fid": 314, - "name": "한도소진율", - "offset": 20, - "start": 280 - }, - { - "fid": 360, - "name": "소진율증가", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "외인한도소진율증가상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10036", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10037": { - "gfid": "2058", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9012, - "name": "기간", - "offset": 2, - "start": 3 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 1, - "start": 5 - }, - { - "fid": 9036, - "name": "정렬구분", - "offset": 1, - "start": 6 - }, - { - "fid": 9077, - "name": "현재가조건", - "offset": 1, - "start": 7 - } - ], - "inputs_name": "외국계창구매매상위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 200 - }, - { - "fid": 202, - "name": "매도거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 206, - "name": "매수거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 210, - "name": "순매수거래량", - "offset": 20, - "start": 260 - }, - { - "fid": 212, - "name": "순매수대금", - "offset": 20, - "start": 280 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 300 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "외국계창구매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10037", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10038": { - "gfid": "2061", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 14 - }, - { - "fid": 9032, - "name": "조회구분", - "offset": 1, - "start": 22 - }, - { - "fid": 9012, - "name": "기간", - "offset": 2, - "start": 23 - } - ], - "inputs_name": "종목별증권사순위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 334, - "name": "회원사명", - "offset": 20, - "start": 40 - }, - { - "fid": 1059, - "name": "매수수량", - "offset": 20, - "start": 60 - }, - { - "fid": 1058, - "name": "매도수량", - "offset": 20, - "start": 80 - }, - { - "fid": 1060, - "name": "누적순매수수량", - "offset": 20, - "start": 100 - } - ], - "multi_outputs_name": "종목별증권사순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1043, - "name": "순위1", - "offset": 20, - "start": 120 - }, - { - "fid": 1044, - "name": "순위2", - "offset": 20, - "start": 140 - }, - { - "fid": 1045, - "name": "순위3", - "offset": 20, - "start": 160 - }, - { - "fid": 1113, - "name": "기간중거래량", - "offset": 20, - "start": 180 - } - ], - "single_outputs_name": "종목별증권사순위_합산", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10038", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10039": { - "gfid": "2062", - "inputs": [ - { - "fid": 9026, - "name": "회원사코드", - "offset": 3, - "start": 0 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 4, - "start": 3 - }, - { - "fid": 9009, - "name": "매매구분", - "offset": 2, - "start": 7 - }, - { - "fid": 9012, - "name": "기간", - "offset": 2, - "start": 9 - } - ], - "inputs_name": "증권사별매매상위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 1111, - "name": "기간중주가등락", - "offset": 20, - "start": 140 - }, - { - "fid": 1112, - "name": "등락율", - "offset": 20, - "start": 160 - }, - { - "fid": 1113, - "name": "기간중거래량", - "offset": 20, - "start": 180 - }, - { - "fid": 210, - "name": "순매수", - "offset": 20, - "start": 200 - }, - { - "fid": 206, - "name": "매수거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 202, - "name": "매도거래량", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "증권사별매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10039", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10040": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "당일주요거래원요청", - "multi_outputs": [ - { - "fid": 1115, - "name": "매도이탈시간", - "offset": 20, - "start": 0 - }, - { - "fid": 1058, - "name": "매도수량", - "offset": 20, - "start": 20 - }, - { - "fid": 1114, - "name": "매도상위이탈원", - "offset": 100, - "start": 40 - }, - { - "fid": 1117, - "name": "매수이탈시간", - "offset": 20, - "start": 140 - }, - { - "fid": 1059, - "name": "매수수량", - "offset": 20, - "start": 160 - }, - { - "fid": 1116, - "name": "매수상위이탈원", - "offset": 100, - "start": 180 - }, - { - "fid": 1118, - "name": "조회일자", - "offset": 20, - "start": 280 - }, - { - "fid": 1119, - "name": "조회시간", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "당일주요거래원", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 166, - "name": "매도거래원별증감1", - "offset": 20, - "start": 0 - }, - { - "fid": 161, - "name": "매도거래원수량1", - "offset": 20, - "start": 20 - }, - { - "fid": 141, - "name": "매도거래원1", - "offset": 100, - "start": 40 - }, - { - "fid": 146, - "name": "매도거래원코드1", - "offset": 20, - "start": 140 - }, - { - "fid": 151, - "name": "매수거래원1", - "offset": 100, - "start": 160 - }, - { - "fid": 156, - "name": "매수거래원코드1", - "offset": 20, - "start": 260 - }, - { - "fid": 171, - "name": "매수거래원수량1", - "offset": 20, - "start": 280 - }, - { - "fid": 176, - "name": "매수거래원별증감1", - "offset": 20, - "start": 300 - }, - { - "fid": 167, - "name": "매도거래원별증감2", - "offset": 20, - "start": 320 - }, - { - "fid": 162, - "name": "매도거래원수량2", - "offset": 20, - "start": 340 - }, - { - "fid": 142, - "name": "매도거래원2", - "offset": 100, - "start": 360 - }, - { - "fid": 147, - "name": "매도거래원코드2", - "offset": 20, - "start": 460 - }, - { - "fid": 152, - "name": "매수거래원2", - "offset": 100, - "start": 480 - }, - { - "fid": 157, - "name": "매수거래원코드2", - "offset": 20, - "start": 580 - }, - { - "fid": 172, - "name": "매수거래원수량2", - "offset": 20, - "start": 600 - }, - { - "fid": 177, - "name": "매수거래원별증감2", - "offset": 20, - "start": 620 - }, - { - "fid": 168, - "name": "매도거래원별증감3", - "offset": 20, - "start": 640 - }, - { - "fid": 163, - "name": "매도거래원수량3", - "offset": 20, - "start": 660 - }, - { - "fid": 143, - "name": "매도거래원3", - "offset": 100, - "start": 680 - }, - { - "fid": 148, - "name": "매도거래원코드3", - "offset": 20, - "start": 780 - }, - { - "fid": 153, - "name": "매수거래원3", - "offset": 100, - "start": 800 - }, - { - "fid": 158, - "name": "매수거래원코드3", - "offset": 20, - "start": 900 - }, - { - "fid": 173, - "name": "매수거래원수량3", - "offset": 20, - "start": 920 - }, - { - "fid": 178, - "name": "매수거래원별증감3", - "offset": 20, - "start": 940 - }, - { - "fid": 169, - "name": "매도거래원별증감4", - "offset": 20, - "start": 960 - }, - { - "fid": 164, - "name": "매도거래원수량4", - "offset": 20, - "start": 980 - }, - { - "fid": 144, - "name": "매도거래원4", - "offset": 100, - "start": 1000 - }, - { - "fid": 149, - "name": "매도거래원코드4", - "offset": 20, - "start": 1100 - }, - { - "fid": 154, - "name": "매수거래원4", - "offset": 100, - "start": 1120 - }, - { - "fid": 159, - "name": "매수거래원코드4", - "offset": 20, - "start": 900 - }, - { - "fid": 174, - "name": "매수거래원수량4", - "offset": 20, - "start": 1240 - }, - { - "fid": 179, - "name": "매수거래원별증감4", - "offset": 20, - "start": 1260 - }, - { - "fid": 170, - "name": "매도거래원별증감5", - "offset": 20, - "start": 1280 - }, - { - "fid": 165, - "name": "매도거래원수량5", - "offset": 20, - "start": 1300 - }, - { - "fid": 145, - "name": "매도거래원5", - "offset": 100, - "start": 1320 - }, - { - "fid": 150, - "name": "매도거래원코드5", - "offset": 20, - "start": 1420 - }, - { - "fid": 155, - "name": "매수거래원5", - "offset": 100, - "start": 1440 - }, - { - "fid": 160, - "name": "매수거래원코드5", - "offset": 20, - "start": 1540 - }, - { - "fid": 175, - "name": "매수거래원수량5", - "offset": 20, - "start": 1560 - }, - { - "fid": 180, - "name": "매수거래원별증감5", - "offset": 20, - "start": 1580 - }, - { - "fid": 262, - "name": "외국계매도추정합변동", - "offset": 20, - "start": 1600 - }, - { - "fid": 261, - "name": "외국계매도추정합", - "offset": 20, - "start": 1620 - }, - { - "fid": 263, - "name": "외국계매수추정합", - "offset": 20, - "start": 1640 - }, - { - "fid": 264, - "name": "외국계매수추정합변동", - "offset": 20, - "start": 1660 - } - ], - "single_outputs_name": "당일주요거래원싱글", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10040", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10041": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9078, - "name": "영웅클럽구분", - "offset": 2, - "start": 6 - } - ], - "inputs_name": "조기종료통화단위요청", - "multi_outputs": [ - { - "fid": 689, - "name": "조기종료여부", - "offset": 20, - "start": 0 - }, - { - "fid": 594, - "name": "통화단위", - "offset": 20, - "start": 20 - } - ], - "multi_outputs_name": "조기종료통화단위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10041", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10042": { - "gfid": "2065", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 14 - }, - { - "fid": 9050, - "name": "조회기간구분", - "offset": 1, - "start": 22 - }, - { - "fid": 9049, - "name": "시점구분", - "offset": 1, - "start": 23 - }, - { - "fid": 9012, - "name": "기간", - "offset": 4, - "start": 24 - }, - { - "fid": 9070, - "name": "정렬기준", - "offset": 1, - "start": 28 - } - ], - "inputs_name": "순매수거래원순위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 20 - }, - { - "fid": 9026, - "name": "회원사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 334, - "name": "회원사명", - "offset": 100, - "start": 40 - } - ], - "multi_outputs_name": "순매수거래원순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10042", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10043": { - "gfid": "2066", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 14 - }, - { - "fid": 9050, - "name": "조회기간구분", - "offset": 1, - "start": 22 - }, - { - "fid": 9049, - "name": "시점구분", - "offset": 1, - "start": 23 - }, - { - "fid": 9012, - "name": "기간", - "offset": 4, - "start": 24 - }, - { - "fid": 9070, - "name": "정렬기준", - "offset": 1, - "start": 28 - }, - { - "fid": 9026, - "name": "회원사코드", - "offset": 3, - "start": 29 - } - ], - "inputs_name": "거래원매물대분석요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 19, - "name": "종가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 202, - "name": "매도량", - "offset": 20, - "start": 60 - }, - { - "fid": 206, - "name": "매수량", - "offset": 20, - "start": 80 - }, - { - "fid": 210, - "name": "순매수수량", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "거래량합", - "offset": 20, - "start": 120 - }, - { - "fid": 1063, - "name": "거래비중", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "거래원매물대분석", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10043", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10044": { - "gfid": "2072", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 8 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 1, - "start": 16 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 17 - } - ], - "inputs_name": "일별기관매매종목요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 1140, - "name": "순매수수량", - "offset": 20, - "start": 120 - }, - { - "fid": 1141, - "name": "순매수금액", - "offset": 20, - "start": 140 - }, - { - "fid": 1142, - "name": "추정평균가", - "offset": 20, - "start": 160 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 180 - }, - { - "fid": 1143, - "name": "평균가대비", - "offset": 20, - "start": 200 - }, - { - "fid": 1144, - "name": "대비율", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "일별기관매매종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10044", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10045": { - "gfid": "2071", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 14 - }, - { - "fid": 9111, - "name": "기관추정단가구분", - "offset": 1, - "start": 22 - }, - { - "fid": 9112, - "name": "외인추정단가구분", - "offset": 1, - "start": 23 - }, - { - "fid": 9012, - "name": "누적기간", - "offset": 1, - "start": 24 - }, - { - "fid": 9050, - "name": "기간구분", - "offset": 1, - "start": 25 - } - ], - "inputs_name": "종목별기관매매추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 1060, - "name": "기관기간누적", - "offset": 20, - "start": 120 - }, - { - "fid": 1140, - "name": "기관일별순매매수량", - "offset": 20, - "start": 140 - }, - { - "fid": 1137, - "name": "외인기간누적", - "offset": 20, - "start": 160 - }, - { - "fid": 1145, - "name": "외인일별순매매수량", - "offset": 20, - "start": 180 - }, - { - "fid": 1146, - "name": "한도소진율", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "종목별기관매매추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1215, - "name": "기관추정평균가", - "offset": 20, - "start": 0 - }, - { - "fid": 1217, - "name": "외인추정평균가", - "offset": 20, - "start": 20 - } - ], - "single_outputs_name": "기관추정평균가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10045", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10046": { - "gfid": "1506", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9007, - "name": "틱구분", - "offset": 1, - "start": 7 - }, - { - "fid": 747, - "name": "체결강도구분", - "offset": 1, - "start": 8 - } - ], - "inputs_name": "체결강도추이시간별요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 80 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 100 - }, - { - "fid": 15, - "name": "거래량", - "offset": 10, - "start": 120 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 130 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 150 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 10, - "start": 170 - }, - { - "fid": 1369, - "name": "체결강도5분", - "offset": 10, - "start": 180 - }, - { - "fid": 1370, - "name": "체결강도20분", - "offset": 10, - "start": 190 - }, - { - "fid": 1371, - "name": "체결강도60분", - "offset": 10, - "start": 200 - } - ], - "multi_outputs_name": "체결강도시간별", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "60", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10046", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10047": { - "gfid": "2121", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9007, - "name": "틱구분", - "offset": 1, - "start": 7 - }, - { - "fid": 747, - "name": "체결강도구분", - "offset": 1, - "start": 8 - } - ], - "inputs_name": "체결강도추이일별요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 15, - "name": "거래량", - "offset": 10, - "start": 100 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 110 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 130 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 10, - "start": 150 - }, - { - "fid": 1369, - "name": "체결강도5분", - "offset": 10, - "start": 160 - }, - { - "fid": 1370, - "name": "체결강도20분", - "offset": 10, - "start": 170 - }, - { - "fid": 1371, - "name": "체결강도60분", - "offset": 10, - "start": 180 - } - ], - "multi_outputs_name": "체결강도일별", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "60", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10047", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10048": { - "gfid": "2899", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ELW일별민감도지표요청", - "multi_outputs": [ - { - "fid": 20, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 671, - "name": "IV", - "offset": 20, - "start": 8 - }, - { - "fid": 672, - "name": "델타", - "offset": 20, - "start": 13 - }, - { - "fid": 673, - "name": "감마", - "offset": 20, - "start": 20 - }, - { - "fid": 674, - "name": "쎄타", - "offset": 20, - "start": 27 - }, - { - "fid": 675, - "name": "베가", - "offset": 20, - "start": 39 - }, - { - "fid": 676, - "name": "로", - "offset": 20, - "start": 51 - }, - { - "fid": 706, - "name": "LP", - "offset": 20, - "start": 63 - } - ], - "multi_outputs_name": "ELW일별민감도지표", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "30", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10048", - "tr_name": "STOCKM", - "tr_name_svr": "", - "tr_type": "3" - }, - "opt10049": { - "gfid": "2898", - "inputs": [ - { - "fid": -1, - "name": "연속구분", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "연속키", - "offset": 4, - "start": 1 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 5 - } - ], - "inputs_name": "ELW투자지표요청", - "multi_outputs": [ - { - "fid": -1, - "name": "시간", - "offset": 6, - "start": 0 - }, - { - "fid": -1, - "name": "패리티", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "프리미엄", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "기어링비율", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "손익분기율", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "현재가", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "레버리지", - "offset": 9, - "start": 0 - } - ], - "multi_outputs_name": "ELW투자지표배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "30", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": -1, - "name": "연속구분", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "연속키", - "offset": 4, - "start": 1 - } - ], - "single_outputs_name": "ELW투자지표", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10049", - "tr_name": "STOCKM", - "tr_name_svr": "", - "tr_type": "3" - }, - "opt10050": { - "gfid": "2038", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ELW민감도지표요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 6, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 10, - "start": 6 - }, - { - "fid": 670, - "name": "ELW이론가", - "offset": 10, - "start": 16 - }, - { - "fid": 671, - "name": "IV", - "offset": 5, - "start": 26 - }, - { - "fid": 672, - "name": "델타", - "offset": 8, - "start": 31 - }, - { - "fid": 673, - "name": "감마", - "offset": 8, - "start": 39 - }, - { - "fid": 674, - "name": "쎄타", - "offset": 12, - "start": 47 - }, - { - "fid": 675, - "name": "베가", - "offset": 12, - "start": 59 - }, - { - "fid": 676, - "name": "로", - "offset": 12, - "start": 71 - }, - { - "fid": 706, - "name": "LP", - "offset": 5, - "start": 83 - } - ], - "multi_outputs_name": "ELW민감도지표배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10050", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10051": { - "gfid": "2300", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 1 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9048, - "name": "기준일자", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "업종별투자자순매수요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 1344, - "name": "업종명", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비부호", - "offset": 20, - "start": 0 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 0 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 0 - }, - { - "fid": 6021, - "name": "증권순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6022, - "name": "보험순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6023, - "name": "투신순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6024, - "name": "은행순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6025, - "name": "종신금순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6026, - "name": "기금순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6027, - "name": "기타법인순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6028, - "name": "개인순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6029, - "name": "외국인순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6030, - "name": "내국인대우외국인순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6032, - "name": "국가순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6033, - "name": "사모펀드순매수", - "offset": 20, - "start": 0 - }, - { - "fid": 6034, - "name": "기관계순매수", - "offset": 20, - "start": 0 - } - ], - "multi_outputs_name": "업종별순매수", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10051", - "tr_name": "STOCKM", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10052": { - "gfid": "2051", - "inputs": [ - { - "fid": 9026, - "name": "회원사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 100, - "start": 20 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 120 - }, - { - "fid": 9022, - "name": "수량구분", - "offset": 20, - "start": 140 - }, - { - "fid": 9077, - "name": "가격구분", - "offset": 20, - "start": 140 - } - ], - "inputs_name": "거래원순간거래량요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 40 - }, - { - "fid": 334, - "name": "거래원명", - "offset": 20, - "start": 180 - }, - { - "fid": 260, - "name": "구분", - "offset": 20, - "start": 200 - }, - { - "fid": 211, - "name": "순간거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 210, - "name": "누적순매수", - "offset": 20, - "start": 240 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 260 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 280 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 300 - }, - { - "fid": 12, - "name": "전일대비", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "거래원순간거래량", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "80", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10052", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10053": { - "gfid": "2064", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "당일상위이탈원요청", - "multi_outputs": [ - { - "fid": 1115, - "name": "매도이탈시간", - "offset": 20, - "start": 0 - }, - { - "fid": 1058, - "name": "매도수량", - "offset": 20, - "start": 20 - }, - { - "fid": 1114, - "name": "매도상위이탈원", - "offset": 100, - "start": 40 - }, - { - "fid": 1117, - "name": "매수이탈시간", - "offset": 20, - "start": 140 - }, - { - "fid": 1059, - "name": "매수수량", - "offset": 20, - "start": 160 - }, - { - "fid": 1116, - "name": "매수상위이탈원", - "offset": 100, - "start": 180 - }, - { - "fid": 1118, - "name": "조회일자", - "offset": 20, - "start": 280 - }, - { - "fid": 1119, - "name": "조회시간", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "당일상위이탈원", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10053", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10054": { - "gfid": "2099", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9075, - "name": "장전구분", - "offset": 1, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9068, - "name": "발동구분", - "offset": 1, - "start": 4 - }, - { - "fid": 9060, - "name": "제외종목", - "offset": 9, - "start": 5 - }, - { - "fid": 9530, - "name": "거래량구분", - "offset": 1, - "start": 6 - }, - { - "fid": 9515, - "name": "최소거래량", - "offset": 12, - "start": 7 - }, - { - "fid": 9516, - "name": "최대거래량", - "offset": 12, - "start": 7 - }, - { - "fid": 9091, - "name": "거래대금구분", - "offset": 1, - "start": 12 - }, - { - "fid": 9092, - "name": "최소거래대금", - "offset": 10, - "start": 7 - }, - { - "fid": 9093, - "name": "최대거래대금", - "offset": 10, - "start": 7 - }, - { - "fid": 9069, - "name": "발동방향", - "offset": 1, - "start": 14 - } - ], - "inputs_name": "변동성완화장치발동종목요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 10, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 10 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 1221, - "name": "발동가격", - "offset": 20, - "start": 20 - }, - { - "fid": 1239, - "name": "동적괴리율", - "offset": 20, - "start": 20 - }, - { - "fid": 1223, - "name": "매매체결처리시각", - "offset": 10, - "start": 20 - }, - { - "fid": 1224, - "name": "VI해제시각", - "offset": 10, - "start": 20 - }, - { - "fid": 1225, - "name": "VI적용구분", - "offset": 10, - "start": 20 - }, - { - "fid": 1237, - "name": "동적기준가격", - "offset": 20, - "start": 20 - }, - { - "fid": 1236, - "name": "정적기준가격", - "offset": 20, - "start": 20 - }, - { - "fid": 1238, - "name": "정적괴리율", - "offset": 20, - "start": 20 - }, - { - "fid": 1489, - "name": "시가대비등락률", - "offset": 20, - "start": 20 - }, - { - "fid": 1490, - "name": "VI발동횟수", - "offset": 10, - "start": 20 - } - ], - "multi_outputs_name": "발동종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10054", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10055": { - "gfid": "1513", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9013, - "name": "당일전일", - "offset": 1, - "start": 6 - } - ], - "inputs_name": "당일전일체결대량요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 160 - }, - { - "fid": 10, - "name": "체결가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 140 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "당일전일체결대량", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "1000", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10055", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10058": { - "gfid": "2072", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 40 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 80 - }, - { - "fid": 9073, - "name": "투자자구분", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "투자자별일별매매종목요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 1140, - "name": "순매도수량", - "offset": 20, - "start": 120 - }, - { - "fid": 1141, - "name": "순매도금액", - "offset": 20, - "start": 140 - }, - { - "fid": 1142, - "name": "추정평균가", - "offset": 20, - "start": 160 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 180 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 200 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 1143, - "name": "평균가대비", - "offset": 20, - "start": 240 - }, - { - "fid": 1144, - "name": "대비율", - "offset": 20, - "start": 260 - }, - { - "fid": 1145, - "name": "기간거래량", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "투자자별일별매매종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10058", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10059": { - "gfid": "2330", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9207, - "name": "단위구분", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "종목별투자자기관별요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 100 - }, - { - "fid": 1859, - "name": "개인투자자", - "offset": 20, - "start": 120 - }, - { - "fid": 1965, - "name": "외국인투자자", - "offset": 20, - "start": 140 - }, - { - "fid": 1977, - "name": "기관계", - "offset": 20, - "start": 160 - }, - { - "fid": 1805, - "name": "금융투자", - "offset": 20, - "start": 180 - }, - { - "fid": 1811, - "name": "보험", - "offset": 20, - "start": 200 - }, - { - "fid": 1817, - "name": "투신", - "offset": 20, - "start": 220 - }, - { - "fid": 1835, - "name": "기타금융", - "offset": 20, - "start": 240 - }, - { - "fid": 1829, - "name": "은행", - "offset": 20, - "start": 260 - }, - { - "fid": 1841, - "name": "연기금등", - "offset": 20, - "start": 280 - }, - { - "fid": 1823, - "name": "사모펀드", - "offset": 20, - "start": 300 - }, - { - "fid": 1847, - "name": "국가", - "offset": 20, - "start": 320 - }, - { - "fid": 1853, - "name": "기타법인", - "offset": 20, - "start": 340 - }, - { - "fid": 1971, - "name": "내외국인", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "종목별투자자기관별", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10059", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10060": { - "gfid": "2330", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9207, - "name": "단위구분", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "종목별투자자기관별차트요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 13, - "name": "누적거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 1859, - "name": "개인투자자", - "offset": 20, - "start": 80 - }, - { - "fid": 1965, - "name": "외국인투자자", - "offset": 20, - "start": 100 - }, - { - "fid": 1977, - "name": "기관계", - "offset": 20, - "start": 120 - }, - { - "fid": 1805, - "name": "금융투자", - "offset": 20, - "start": 140 - }, - { - "fid": 1811, - "name": "보험", - "offset": 20, - "start": 160 - }, - { - "fid": 1817, - "name": "투신", - "offset": 20, - "start": 180 - }, - { - "fid": 1835, - "name": "기타금융", - "offset": 20, - "start": 200 - }, - { - "fid": 1829, - "name": "은행", - "offset": 20, - "start": 220 - }, - { - "fid": 1841, - "name": "연기금등", - "offset": 20, - "start": 240 - }, - { - "fid": 1823, - "name": "사모펀드", - "offset": 20, - "start": 260 - }, - { - "fid": 1847, - "name": "국가", - "offset": 20, - "start": 280 - }, - { - "fid": 1853, - "name": "기타법인", - "offset": 20, - "start": 300 - }, - { - "fid": 1971, - "name": "내외국인", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "종목별투자자기관별차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10060", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10061": { - "gfid": "2329", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 40 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 80 - }, - { - "fid": 9207, - "name": "단위구분", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "종목별투자자기관별합계요청", - "multi_outputs": [ - { - "fid": 6008, - "name": "개인투자자", - "offset": 20, - "start": 120 - }, - { - "fid": 6009, - "name": "외국인투자자", - "offset": 20, - "start": 140 - }, - { - "fid": 6014, - "name": "기관계", - "offset": 20, - "start": 160 - }, - { - "fid": 6001, - "name": "금융투자", - "offset": 20, - "start": 180 - }, - { - "fid": 6002, - "name": "보험", - "offset": 20, - "start": 200 - }, - { - "fid": 6003, - "name": "투신", - "offset": 20, - "start": 220 - }, - { - "fid": 6005, - "name": "기타금융", - "offset": 20, - "start": 240 - }, - { - "fid": 6004, - "name": "은행", - "offset": 20, - "start": 260 - }, - { - "fid": 6006, - "name": "연기금등", - "offset": 20, - "start": 280 - }, - { - "fid": 6013, - "name": "사모펀드", - "offset": 20, - "start": 300 - }, - { - "fid": 6012, - "name": "국가", - "offset": 20, - "start": 320 - }, - { - "fid": 6007, - "name": "기타법인", - "offset": 20, - "start": 340 - }, - { - "fid": 6010, - "name": "내외국인", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "종목별투자자기관별합계", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "1", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10061", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10062": { - "gfid": "2078", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9009, - "name": "정렬조건", - "offset": 20, - "start": 80 - }, - { - "fid": 9207, - "name": "단위구분", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "동일순매매순위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 1134, - "name": "기관순매매수량", - "offset": 20, - "start": 240 - }, - { - "fid": 1135, - "name": "기관순매매금액", - "offset": 20, - "start": 260 - }, - { - "fid": 1142, - "name": "기관순매매평균가", - "offset": 20, - "start": 280 - }, - { - "fid": 1414, - "name": "외인순매매수량", - "offset": 20, - "start": 300 - }, - { - "fid": 1415, - "name": "외인순매매금액", - "offset": 20, - "start": 320 - }, - { - "fid": 1148, - "name": "외인순매매평균가", - "offset": 20, - "start": 340 - }, - { - "fid": 1140, - "name": "순매매수량", - "offset": 20, - "start": 360 - }, - { - "fid": 1141, - "name": "순매매금액", - "offset": 20, - "start": 380 - } - ], - "multi_outputs_name": "동일순매매순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10062", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10063": { - "gfid": "2327", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 3, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 1, - "start": 3 - }, - { - "fid": 9073, - "name": "투자자별", - "offset": 20, - "start": 4 - }, - { - "fid": 9112, - "name": "외국계전체", - "offset": 1, - "start": 24 - }, - { - "fid": 9177, - "name": "동시순매수구분", - "offset": 1, - "start": 25 - } - ], - "inputs_name": "장중투자자별매매요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 12, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 12 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 112 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 132 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 152 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 172 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 192 - }, - { - "fid": 212, - "name": "순매수금액", - "offset": 20, - "start": 212 - }, - { - "fid": 736, - "name": "이전순매수금액", - "offset": 20, - "start": 232 - }, - { - "fid": 213, - "name": "순매수금액증감", - "offset": 20, - "start": 252 - }, - { - "fid": 208, - "name": "매수금액", - "offset": 20, - "start": 272 - }, - { - "fid": 209, - "name": "매수금액증감", - "offset": 20, - "start": 292 - }, - { - "fid": 204, - "name": "매도금액", - "offset": 20, - "start": 312 - }, - { - "fid": 205, - "name": "매도금액증감", - "offset": 20, - "start": 332 - }, - { - "fid": 210, - "name": "순매수수량", - "offset": 20, - "start": 352 - }, - { - "fid": 217, - "name": "이점시전순매수수량", - "offset": 20, - "start": 372 - }, - { - "fid": 218, - "name": "순매수증감", - "offset": 20, - "start": 392 - }, - { - "fid": 206, - "name": "매수수량", - "offset": 20, - "start": 412 - }, - { - "fid": 207, - "name": "매수수량증감", - "offset": 20, - "start": 432 - }, - { - "fid": 202, - "name": "매도수량", - "offset": 20, - "start": 452 - }, - { - "fid": 203, - "name": "매도수량증감", - "offset": 20, - "start": 472 - } - ], - "multi_outputs_name": "장중투자자별매매", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "500", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10063", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10064": { - "gfid": "2318", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "장중투자자별매매차트요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 100, - "start": 0 - }, - { - "fid": 6009, - "name": "외국인투자자", - "offset": 20, - "start": 100 - }, - { - "fid": 6014, - "name": "기관계", - "offset": 20, - "start": 120 - }, - { - "fid": 6003, - "name": "투신", - "offset": 20, - "start": 140 - }, - { - "fid": 6002, - "name": "보험", - "offset": 20, - "start": 160 - }, - { - "fid": 6004, - "name": "은행", - "offset": 20, - "start": 180 - }, - { - "fid": 6006, - "name": "연기금등", - "offset": 20, - "start": 200 - }, - { - "fid": 6007, - "name": "기타법인", - "offset": 20, - "start": 220 - }, - { - "fid": 6012, - "name": "국가", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "장중투자자별매매차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10064", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10065": { - "gfid": "2094", - "inputs": [ - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9073, - "name": "기관구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "장중투자자별매매상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 1140, - "name": "매도량", - "offset": 20, - "start": 120 - }, - { - "fid": 1141, - "name": "매수량", - "offset": 20, - "start": 140 - }, - { - "fid": 1142, - "name": "순매도", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "장중투자자별매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10065", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10066": { - "gfid": "2320", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9032, - "name": "매매구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "장중투자자별매매차트요청", - "multi_outputs": [ - { - "fid": 301, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 6008, - "name": "개인투자자", - "offset": 20, - "start": 220 - }, - { - "fid": 6009, - "name": "외국인투자자", - "offset": 20, - "start": 240 - }, - { - "fid": 6014, - "name": "기관계", - "offset": 20, - "start": 260 - }, - { - "fid": 6001, - "name": "금융투자", - "offset": 20, - "start": 280 - }, - { - "fid": 6002, - "name": "보험", - "offset": 20, - "start": 300 - }, - { - "fid": 6003, - "name": "투신", - "offset": 20, - "start": 320 - }, - { - "fid": 6005, - "name": "기타금융", - "offset": 20, - "start": 340 - }, - { - "fid": 6004, - "name": "은행", - "offset": 20, - "start": 360 - }, - { - "fid": 6006, - "name": "연기금등", - "offset": 20, - "start": 380 - }, - { - "fid": 6013, - "name": "사모펀드", - "offset": 20, - "start": 400 - }, - { - "fid": 6012, - "name": "국가", - "offset": 20, - "start": 420 - }, - { - "fid": 6007, - "name": "기타법인", - "offset": 20, - "start": 440 - } - ], - "multi_outputs_name": "장중투자자별매매차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10066", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10067": { - "gfid": "2216", - "inputs": [ - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "대차거래내역요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 389, - "name": "종목코드", - "offset": 20, - "start": 100 - }, - { - "fid": 312, - "name": "대차거래체결주수", - "offset": 20, - "start": 120 - }, - { - "fid": 470, - "name": "대차거래상환주수", - "offset": 20, - "start": 140 - }, - { - "fid": 471, - "name": "잔고주수", - "offset": 20, - "start": 160 - }, - { - "fid": 472, - "name": "잔고금액", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "대차거래내역", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10067", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10068": { - "gfid": "2217", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9002, - "name": "전체구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "대차거래추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 20 - }, - { - "fid": 313, - "name": "대차거래체결주수", - "offset": 20, - "start": 40 - }, - { - "fid": 473, - "name": "대차거래상환주수", - "offset": 20, - "start": 60 - }, - { - "fid": 477, - "name": "대차거래증감", - "offset": 20, - "start": 80 - }, - { - "fid": 474, - "name": "잔고주수", - "offset": 20, - "start": 100 - }, - { - "fid": 475, - "name": "잔고금액", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "대차거래추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10068", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10069": { - "gfid": "2218", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "대차거래상위10종목요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 389, - "name": "종목코드", - "offset": 20, - "start": 100 - }, - { - "fid": 312, - "name": "대차거래체결주수", - "offset": 20, - "start": 120 - }, - { - "fid": 470, - "name": "대차거래상환주수", - "offset": 20, - "start": 140 - }, - { - "fid": 471, - "name": "잔고주수", - "offset": 20, - "start": 160 - }, - { - "fid": 472, - "name": "잔고금액", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "대차거래상위10종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1041, - "name": "대차거래체결주수합", - "offset": 20, - "start": 0 - }, - { - "fid": 1042, - "name": "대차거래상환주수합", - "offset": 20, - "start": 20 - }, - { - "fid": 1043, - "name": "잔고주수합", - "offset": 20, - "start": 40 - }, - { - "fid": 1044, - "name": "잔고금액합", - "offset": 20, - "start": 60 - }, - { - "fid": 1045, - "name": "대차거래체결주수비율", - "offset": 20, - "start": 80 - }, - { - "fid": 1046, - "name": "대차거래상환주수비율", - "offset": 20, - "start": 100 - }, - { - "fid": 1047, - "name": "잔고주수비율", - "offset": 20, - "start": 120 - }, - { - "fid": 1048, - "name": "잔고금액비율", - "offset": 20, - "start": 140 - } - ], - "single_outputs_name": "대차거래상위10종목합계", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10069", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10070": { - "gfid": "2064", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "당일주요거래원요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 166, - "name": "매도거래원별증감1", - "offset": 20, - "start": 0 - }, - { - "fid": 161, - "name": "매도거래원수량1", - "offset": 20, - "start": 20 - }, - { - "fid": 141, - "name": "매도거래원1", - "offset": 100, - "start": 40 - }, - { - "fid": 146, - "name": "매도거래원코드1", - "offset": 20, - "start": 140 - }, - { - "fid": 151, - "name": "매수거래원1", - "offset": 100, - "start": 160 - }, - { - "fid": 156, - "name": "매수거래원코드1", - "offset": 20, - "start": 260 - }, - { - "fid": 171, - "name": "매수거래원수량1", - "offset": 20, - "start": 280 - }, - { - "fid": 176, - "name": "매수거래원별증감1", - "offset": 20, - "start": 300 - }, - { - "fid": 167, - "name": "매도거래원별증감2", - "offset": 20, - "start": 320 - }, - { - "fid": 162, - "name": "매도거래원수량2", - "offset": 20, - "start": 340 - }, - { - "fid": 142, - "name": "매도거래원2", - "offset": 100, - "start": 360 - }, - { - "fid": 147, - "name": "매도거래원코드2", - "offset": 20, - "start": 460 - }, - { - "fid": 152, - "name": "매수거래원2", - "offset": 100, - "start": 480 - }, - { - "fid": 157, - "name": "매수거래원코드2", - "offset": 20, - "start": 580 - }, - { - "fid": 172, - "name": "매수거래원수량2", - "offset": 20, - "start": 600 - }, - { - "fid": 177, - "name": "매수거래원별증감2", - "offset": 20, - "start": 620 - }, - { - "fid": 168, - "name": "매도거래원별증감3", - "offset": 20, - "start": 640 - }, - { - "fid": 163, - "name": "매도거래원수량3", - "offset": 20, - "start": 660 - }, - { - "fid": 143, - "name": "매도거래원3", - "offset": 100, - "start": 680 - }, - { - "fid": 148, - "name": "매도거래원코드3", - "offset": 20, - "start": 780 - }, - { - "fid": 153, - "name": "매수거래원3", - "offset": 100, - "start": 800 - }, - { - "fid": 158, - "name": "매수거래원코드3", - "offset": 20, - "start": 900 - }, - { - "fid": 173, - "name": "매수거래원수량3", - "offset": 20, - "start": 920 - }, - { - "fid": 178, - "name": "매수거래원별증감3", - "offset": 20, - "start": 940 - }, - { - "fid": 169, - "name": "매도거래원별증감4", - "offset": 20, - "start": 960 - }, - { - "fid": 164, - "name": "매도거래원수량4", - "offset": 20, - "start": 980 - }, - { - "fid": 144, - "name": "매도거래원4", - "offset": 100, - "start": 1000 - }, - { - "fid": 149, - "name": "매도거래원코드4", - "offset": 20, - "start": 1100 - }, - { - "fid": 154, - "name": "매수거래원4", - "offset": 100, - "start": 1120 - }, - { - "fid": 174, - "name": "매수거래원수량4", - "offset": 20, - "start": 1240 - }, - { - "fid": 179, - "name": "매수거래원별증감4", - "offset": 20, - "start": 1260 - }, - { - "fid": 170, - "name": "매도거래원별증감5", - "offset": 20, - "start": 1280 - }, - { - "fid": 165, - "name": "매도거래원수량5", - "offset": 20, - "start": 1300 - }, - { - "fid": 145, - "name": "매도거래원5", - "offset": 100, - "start": 1320 - }, - { - "fid": 150, - "name": "매도거래원코드5", - "offset": 20, - "start": 1420 - }, - { - "fid": 155, - "name": "매수거래원5", - "offset": 100, - "start": 1440 - }, - { - "fid": 160, - "name": "매수거래원코드5", - "offset": 20, - "start": 1540 - }, - { - "fid": 175, - "name": "매수거래원수량5", - "offset": 20, - "start": 1560 - }, - { - "fid": 180, - "name": "매수거래원별증감5", - "offset": 20, - "start": 1580 - }, - { - "fid": 262, - "name": "외국계매도추정합변동", - "offset": 20, - "start": 1600 - }, - { - "fid": 261, - "name": "외국계매도추정합", - "offset": 20, - "start": 1620 - }, - { - "fid": 263, - "name": "외국계매수추정합", - "offset": 20, - "start": 1640 - }, - { - "fid": 264, - "name": "외국계매수추정합변동", - "offset": 20, - "start": 1660 - } - ], - "single_outputs_name": "당일주요거래원", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10070", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10071": { - "gfid": "1500", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간구분", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "시간대별전일비거래비중요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 80 - }, - { - "fid": 15, - "name": "체결거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 31, - "name": "순간비율", - "offset": 20, - "start": 140 - }, - { - "fid": 30, - "name": "누적비율", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "시간대별전일비거래비중", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10071", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10072": { - "gfid": "8514", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "일자별종목별실현손익요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 940, - "name": "당일hts매도수수료", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 140 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 160 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 180 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 200 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 220 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 240 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 260 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 280 - }, - { - "fid": 985, - "name": "인출가능금액", - "offset": 20, - "start": 300 - }, - { - "fid": 8021, - "name": "대출일", - "offset": 20, - "start": 320 - }, - { - "fid": 8020, - "name": "신용구분", - "offset": 20, - "start": 340 - }, - { - "fid": 9001, - "name": "종목코드1", - "offset": 20, - "start": 360 - }, - { - "fid": 944, - "name": "당일매도손익1", - "offset": 20, - "start": 380 - } - ], - "multi_outputs_name": "일자별종목별실현손익", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10072", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10073": { - "gfid": "8513", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9005, - "name": "시작일자", - "offset": 20, - "start": 40 - }, - { - "fid": 9004, - "name": "종료일자", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "일자별종목별실현손익요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 940, - "name": "당일hts매도수수료", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 140 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 160 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 180 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 200 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 220 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 240 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 260 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 280 - }, - { - "fid": 985, - "name": "인출가능금액", - "offset": 20, - "start": 300 - }, - { - "fid": 8021, - "name": "대출일", - "offset": 20, - "start": 320 - }, - { - "fid": 8020, - "name": "신용구분", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "일자별종목별실현손익", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "300", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10073", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10074": { - "gfid": "8523", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "시작일자", - "offset": 20, - "start": 40 - }, - { - "fid": 9004, - "name": "종료일자", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "일자별실현손익요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 932, - "name": "매수금액", - "offset": 20, - "start": 20 - }, - { - "fid": 933, - "name": "매도금액", - "offset": 20, - "start": 40 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 60 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 80 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 100 - } - ], - "multi_outputs_name": "일자별실현손익", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "300", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 932, - "name": "총매수금액", - "offset": 20, - "start": 20 - }, - { - "fid": 933, - "name": "총매도금액", - "offset": 20, - "start": 40 - }, - { - "fid": 944, - "name": "실현손익", - "offset": 20, - "start": 60 - }, - { - "fid": 938, - "name": "매매수수료", - "offset": 20, - "start": 80 - }, - { - "fid": 939, - "name": "매매세금", - "offset": 20, - "start": 100 - } - ], - "single_outputs_name": "일자별실현손익단일", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10074", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10075": { - "gfid": "8500", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9037, - "name": "전체종목구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9204, - "name": "매매구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 60 - }, - { - "fid": 9206, - "name": "체결구분", - "offset": 20, - "start": 180 - } - ], - "inputs_name": "미체결요청", - "multi_outputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9203, - "name": "주문번호", - "offset": 20, - "start": 20 - }, - { - "fid": 9205, - "name": "관리사번", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 60 - }, - { - "fid": 912, - "name": "업무구분", - "offset": 20, - "start": 80 - }, - { - "fid": 913, - "name": "주문상태", - "offset": 20, - "start": 100 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 120 - }, - { - "fid": 900, - "name": "주문수량", - "offset": 20, - "start": 220 - }, - { - "fid": 901, - "name": "주문가격", - "offset": 20, - "start": 240 - }, - { - "fid": 902, - "name": "미체결수량", - "offset": 20, - "start": 260 - }, - { - "fid": 903, - "name": "체결누계금액", - "offset": 20, - "start": 280 - }, - { - "fid": 904, - "name": "원주문번호", - "offset": 20, - "start": 300 - }, - { - "fid": 905, - "name": "주문구분", - "offset": 20, - "start": 320 - }, - { - "fid": 906, - "name": "매매구분", - "offset": 20, - "start": 340 - }, - { - "fid": 908, - "name": "시간", - "offset": 20, - "start": 380 - }, - { - "fid": 909, - "name": "체결번호", - "offset": 20, - "start": 400 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 420 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 440 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 460 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 480 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 500 - }, - { - "fid": 914, - "name": "단위체결가", - "offset": 20, - "start": 520 - }, - { - "fid": 915, - "name": "단위체결량", - "offset": 20, - "start": 540 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 560 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 580 - }, - { - "fid": 8000, - "name": "개인투자자", - "offset": 20, - "start": 600 - } - ], - "multi_outputs_name": "미체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10075", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10076": { - "gfid": "8500", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9037, - "name": "조회구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9204, - "name": "매도수구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 60 - }, - { - "fid": 9202, - "name": "비밀번호", - "offset": 100, - "start": 80 - }, - { - "fid": 9203, - "name": "주문번호", - "offset": 20, - "start": 180 - }, - { - "fid": 9206, - "name": "체결구분", - "offset": 20, - "start": 180 - } - ], - "inputs_name": "체결요청", - "multi_outputs": [ - { - "fid": 9203, - "name": "주문번호", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 905, - "name": "주문구분", - "offset": 20, - "start": 120 - }, - { - "fid": 901, - "name": "주문가격", - "offset": 20, - "start": 140 - }, - { - "fid": 900, - "name": "주문수량", - "offset": 20, - "start": 160 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 180 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 200 - }, - { - "fid": 902, - "name": "미체결수량", - "offset": 20, - "start": 220 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 240 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 260 - }, - { - "fid": 913, - "name": "주문상태", - "offset": 20, - "start": 280 - }, - { - "fid": 906, - "name": "매매구분", - "offset": 20, - "start": 300 - }, - { - "fid": 904, - "name": "원주문번호", - "offset": 20, - "start": 320 - }, - { - "fid": 908, - "name": "주문시간", - "offset": 20, - "start": 340 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10076", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10077": { - "gfid": "8508", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9202, - "name": "비밀번호", - "offset": 100, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 100, - "start": 120 - } - ], - "inputs_name": "당일실현손익상세요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 100 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 120 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 140 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 160 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 180 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 200 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 220 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "당일실현손익상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "300", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 944, - "name": "당일실현손익", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "당일실현손익", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10077", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10078": { - "gfid": "2060", - "inputs": [ - { - "fid": 9026, - "name": "회원사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 100, - "start": 20 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 120 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 140 - } - ], - "inputs_name": "증권사별종목매매동향요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 100, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 120 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 140 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 160 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 180 - }, - { - "fid": 210, - "name": "순매수수량", - "offset": 20, - "start": 200 - }, - { - "fid": 206, - "name": "매수수량", - "offset": 20, - "start": 220 - }, - { - "fid": 202, - "name": "매도수량", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "증권사별종목매매동향", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10078", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10079": { - "gfid": "3001", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "틱범위", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식틱차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 120 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 140 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 180 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 200 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 220 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "주식틱차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 3501, - "name": "마지막틱갯수", - "offset": 20, - "start": 220 - } - ], - "single_outputs_name": "주식틱차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10079", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10080": { - "gfid": "3002", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "틱범위", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식분봉차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 120 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 140 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 180 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 200 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 220 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "주식분봉차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "주식분차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10080", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10081": { - "gfid": "3003", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식일봉차트조회요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 80 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 100 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 120 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 140 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 160 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 180 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 200 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 220 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 240 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 260 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "주식일봉차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "주식일봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10081", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10082": { - "gfid": "3004", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9005, - "name": "끝일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식주봉차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 80 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 100 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 120 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 140 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 160 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 180 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 200 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 220 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 240 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 260 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "주식주봉차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "300", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "주식주봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10082", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10083": { - "gfid": "3005", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9005, - "name": "끝일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식월봉차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 80 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 100 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 120 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 140 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 160 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 180 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 200 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 220 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 240 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 260 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "주식월봉차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "240", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "주식월봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10083", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10084": { - "gfid": "1506", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9013, - "name": "당일전일", - "offset": 1, - "start": 6 - }, - { - "fid": 9007, - "name": "틱분", - "offset": 1, - "start": 7 - }, - { - "fid": 9002, - "name": "시간", - "offset": 4, - "start": 8 - } - ], - "inputs_name": "당일전일체결요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 60 - }, - { - "fid": 27, - "name": "우선매도호가단위", - "offset": 20, - "start": 80 - }, - { - "fid": 28, - "name": "우선매수호가단위", - "offset": 20, - "start": 100 - }, - { - "fid": 15, - "name": "체결거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "sign", - "offset": 20, - "start": 140 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 160 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 180 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "당일전일체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10084", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10085": { - "gfid": "8510", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "계좌수익률요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 50, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 931, - "name": "매입가", - "offset": 20, - "start": 20 - }, - { - "fid": 932, - "name": "매입금액", - "offset": 20, - "start": 20 - }, - { - "fid": 930, - "name": "보유수량", - "offset": 20, - "start": 20 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 60 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 80 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 100 - }, - { - "fid": 917, - "name": "신용구분", - "offset": 20, - "start": 100 - }, - { - "fid": 916, - "name": "대출일", - "offset": 20, - "start": 100 - }, - { - "fid": 8002, - "name": "결제잔고", - "offset": 20, - "start": 100 - }, - { - "fid": 933, - "name": "청산가능수량", - "offset": 20, - "start": 100 - }, - { - "fid": 957, - "name": "신용금액", - "offset": 20, - "start": 100 - }, - { - "fid": 958, - "name": "신용이자", - "offset": 20, - "start": 100 - }, - { - "fid": 918, - "name": "만기일", - "offset": 20, - "start": 100 - } - ], - "multi_outputs_name": "계좌수익률", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10085", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10086": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9004, - "name": "조회일자", - "offset": 8, - "start": 6 - }, - { - "fid": 9036, - "name": "표시구분", - "offset": 1, - "start": 8 - } - ], - "inputs_name": "일별주가요청", - "multi_outputs": [ - { - "fid": 22, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 20 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 40 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 80 - }, - { - "fid": 11, - "name": "전일비", - "offset": 20, - "start": 100 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 120 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 140 - }, - { - "fid": 14, - "name": "금액(백만)", - "offset": 20, - "start": 160 - }, - { - "fid": 329, - "name": "신용비", - "offset": 20, - "start": 180 - }, - { - "fid": 1140, - "name": "개인", - "offset": 20, - "start": 200 - }, - { - "fid": 1136, - "name": "기관", - "offset": 20, - "start": 220 - }, - { - "fid": 1137, - "name": "외인수량", - "offset": 20, - "start": 240 - }, - { - "fid": 1138, - "name": "외국계", - "offset": 20, - "start": 260 - }, - { - "fid": 1139, - "name": "프로그램", - "offset": 20, - "start": 280 - }, - { - "fid": 1066, - "name": "외인비", - "offset": 20, - "start": 300 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 180 - }, - { - "fid": 1066, - "name": "외인보유", - "offset": 20, - "start": 200 - }, - { - "fid": 1066, - "name": "외인비중", - "offset": 20, - "start": 220 - }, - { - "fid": 1137, - "name": "외인순매수", - "offset": 20, - "start": 240 - }, - { - "fid": 1136, - "name": "기관순매수", - "offset": 20, - "start": 260 - }, - { - "fid": 1140, - "name": "개인순매수", - "offset": 20, - "start": 280 - }, - { - "fid": 329, - "name": "신용잔고율", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "일별주가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10086", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10087": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "시간외단일가요청", - "multi_outputs": [ - { - "fid": 21, - "name": "호가잔량기준시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10085, - "name": "시간외단일가_매도호가직전대비5", - "offset": 20, - "start": 20 - }, - { - "fid": 10084, - "name": "시간외단일가_매도호가직전대비4", - "offset": 20, - "start": 40 - }, - { - "fid": 10083, - "name": "시간외단일가_매도호가직전대비3", - "offset": 20, - "start": 60 - }, - { - "fid": 10082, - "name": "시간외단일가_매도호가직전대비2", - "offset": 20, - "start": 80 - }, - { - "fid": 10081, - "name": "시간외단일가_매도호가직전대비1", - "offset": 20, - "start": 100 - }, - { - "fid": 10065, - "name": "시간외단일가_매도호가수량5", - "offset": 20, - "start": 120 - }, - { - "fid": 10064, - "name": "시간외단일가_매도호가수량4", - "offset": 20, - "start": 140 - }, - { - "fid": 10063, - "name": "시간외단일가_매도호가수량3", - "offset": 20, - "start": 160 - }, - { - "fid": 10062, - "name": "시간외단일가_매도호가수량2", - "offset": 20, - "start": 180 - }, - { - "fid": 10061, - "name": "시간외단일가_매도호가수량1", - "offset": 20, - "start": 200 - }, - { - "fid": 10045, - "name": "시간외단일가_매도호가5", - "offset": 20, - "start": 220 - }, - { - "fid": 10044, - "name": "시간외단일가_매도호가4", - "offset": 20, - "start": 240 - }, - { - "fid": 10043, - "name": "시간외단일가_매도호가3", - "offset": 20, - "start": 260 - }, - { - "fid": 10042, - "name": "시간외단일가_매도호가2", - "offset": 20, - "start": 280 - }, - { - "fid": 10041, - "name": "시간외단일가_매도호가1", - "offset": 20, - "start": 300 - }, - { - "fid": 10051, - "name": "시간외단일가_매수호가1", - "offset": 20, - "start": 320 - }, - { - "fid": 10052, - "name": "시간외단일가_매수호가2", - "offset": 20, - "start": 340 - }, - { - "fid": 10053, - "name": "시간외단일가_매수호가3", - "offset": 20, - "start": 360 - }, - { - "fid": 10054, - "name": "시간외단일가_매수호가4", - "offset": 20, - "start": 380 - }, - { - "fid": 10055, - "name": "시간외단일가_매수호가5", - "offset": 20, - "start": 400 - }, - { - "fid": 10071, - "name": "시간외단일가_매수호가수량1", - "offset": 20, - "start": 420 - }, - { - "fid": 10072, - "name": "시간외단일가_매수호가수량2", - "offset": 20, - "start": 440 - }, - { - "fid": 10073, - "name": "시간외단일가_매수호가수량3", - "offset": 20, - "start": 460 - }, - { - "fid": 10074, - "name": "시간외단일가_매수호가수량4", - "offset": 20, - "start": 480 - }, - { - "fid": 10075, - "name": "시간외단일가_매수호가수량5", - "offset": 20, - "start": 500 - }, - { - "fid": 10091, - "name": "시간외단일가_매수호가직전대비1", - "offset": 20, - "start": 520 - }, - { - "fid": 10092, - "name": "시간외단일가_매수호가직전대비2", - "offset": 20, - "start": 540 - }, - { - "fid": 10093, - "name": "시간외단일가_매수호가직전대비3", - "offset": 20, - "start": 560 - }, - { - "fid": 10094, - "name": "시간외단일가_매수호가직전대비4", - "offset": 20, - "start": 580 - }, - { - "fid": 10095, - "name": "시간외단일가_매수호가직전대비5", - "offset": 20, - "start": 600 - }, - { - "fid": 10121, - "name": "시간외단일가_매도호가총잔량", - "offset": 20, - "start": 620 - }, - { - "fid": 10125, - "name": "시간외단일가_매수호가총잔량", - "offset": 20, - "start": 640 - }, - { - "fid": 122, - "name": "매도호가총잔량직전대비", - "offset": 20, - "start": 660 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 680 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 700 - }, - { - "fid": 126, - "name": "매수호가총잔량직전대비", - "offset": 20, - "start": 720 - }, - { - "fid": 132, - "name": "시간외매도호가총잔량직전대비", - "offset": 20, - "start": 740 - }, - { - "fid": 131, - "name": "시간외매도호가총잔량", - "offset": 20, - "start": 760 - }, - { - "fid": 135, - "name": "시간외매수호가총잔량", - "offset": 20, - "start": 780 - }, - { - "fid": 136, - "name": "시간외매수호가총잔량직전대비", - "offset": 20, - "start": 800 - }, - { - "fid": 10010, - "name": "시간외단일가_현재가", - "offset": 20, - "start": 1000 - }, - { - "fid": 10025, - "name": "시간외단일가_전일대비기호", - "offset": 20, - "start": 1000 - }, - { - "fid": 10011, - "name": "시간외단일가_전일대비", - "offset": 20, - "start": 1000 - }, - { - "fid": 10012, - "name": "시간외단일가_등락률", - "offset": 20, - "start": 1000 - }, - { - "fid": 10013, - "name": "시간외단일가_누적거래량", - "offset": 20, - "start": 1000 - } - ], - "multi_outputs_name": "시간외단일가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10087", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10094": { - "gfid": "3006", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9005, - "name": "끝일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9055, - "name": "수정주가구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "주식년봉차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 80 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 100 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 120 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 140 - }, - { - "fid": 3502, - "name": "수정주가구분", - "offset": 20, - "start": 160 - }, - { - "fid": 3503, - "name": "수정비율", - "offset": 20, - "start": 180 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 200 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 220 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 240 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 260 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "주식년봉차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "30", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "주식년봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10094", - "tr_name": "SCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10098": { - "gfid": "2032", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9009, - "name": "정렬기준", - "offset": 20, - "start": 20 - }, - { - "fid": 9060, - "name": "종목조건", - "offset": 20, - "start": 40 - }, - { - "fid": 9022, - "name": "거래량조건", - "offset": 20, - "start": 60 - }, - { - "fid": 9062, - "name": "신용조건", - "offset": 20, - "start": 80 - }, - { - "fid": 9080, - "name": "거래대금", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "시간외단일가등락율순위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 140, - "start": 40 - }, - { - "fid": 10010, - "name": "현재가", - "offset": 20, - "start": 180 - }, - { - "fid": 10025, - "name": "전일대비기호", - "offset": 20, - "start": 200 - }, - { - "fid": 10011, - "name": "전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 10012, - "name": "등락률", - "offset": 20, - "start": 240 - }, - { - "fid": 10121, - "name": "매도총잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 10125, - "name": "매수총잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 10013, - "name": "누적거래량", - "offset": 20, - "start": 300 - }, - { - "fid": 10014, - "name": "누적거래대금", - "offset": 20, - "start": 320 - }, - { - "fid": 10, - "name": "당일종가", - "offset": 20, - "start": 340 - }, - { - "fid": 12, - "name": "당일종가등락률", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "시간외단일가등락율순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10098", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10131": { - "gfid": "2079", - "inputs": [ - { - "fid": 9305, - "name": "기간", - "offset": 3, - "start": 0 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 8, - "start": 3 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 8, - "start": 11 - }, - { - "fid": 9008, - "name": "장구분", - "offset": 3, - "start": 19 - }, - { - "fid": 9032, - "name": "순매도수구분", - "offset": 1, - "start": 22 - }, - { - "fid": 9057, - "name": "종목업종구분", - "offset": 1, - "start": 23 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 1, - "start": 24 - } - ], - "inputs_name": "기관외국인연속매매현황요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 10, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 12, - "start": 10 - }, - { - "fid": 302, - "name": "종목명", - "offset": 120, - "start": 22 - }, - { - "fid": 1112, - "name": "기간중주가등락률", - "offset": 20, - "start": 142 - }, - { - "fid": 1135, - "name": "기관순매매금액", - "offset": 20, - "start": 162 - }, - { - "fid": 1134, - "name": "기관순매매량", - "offset": 20, - "start": 182 - }, - { - "fid": 877, - "name": "기관계연속순매수일수", - "offset": 20, - "start": 202 - }, - { - "fid": 878, - "name": "기관계연속순매수량", - "offset": 20, - "start": 222 - }, - { - "fid": 879, - "name": "기관계연속순매수금액", - "offset": 20, - "start": 242 - }, - { - "fid": 1414, - "name": "외국인순매매량", - "offset": 20, - "start": 262 - }, - { - "fid": 1415, - "name": "외국인순매매액", - "offset": 20, - "start": 282 - }, - { - "fid": 880, - "name": "외국인연속순매수일수", - "offset": 20, - "start": 302 - }, - { - "fid": 881, - "name": "외국인연속순매수량", - "offset": 20, - "start": 322 - }, - { - "fid": 882, - "name": "외국인연속순매수금액", - "offset": 20, - "start": 342 - }, - { - "fid": 1140, - "name": "순매매량", - "offset": 20, - "start": 362 - }, - { - "fid": 1141, - "name": "순매매액", - "offset": 20, - "start": 382 - }, - { - "fid": 883, - "name": "합계연속순매수일수", - "offset": 20, - "start": 402 - }, - { - "fid": 884, - "name": "합계연속순매매수량", - "offset": 20, - "start": 422 - }, - { - "fid": 885, - "name": "합계연속순매수금액", - "offset": 20, - "start": 442 - } - ], - "multi_outputs_name": "기관외국인연속매매현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt10131", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt10170": { - "gfid": "8516", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": 9202, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 8, - "start": 74 - }, - { - "fid": 9207, - "name": "단주구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9020, - "name": "현금신용구분", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "당일매매일지요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 120, - "start": 0 - }, - { - "fid": 8011, - "name": "매수평균가", - "offset": 20, - "start": 120 - }, - { - "fid": 8012, - "name": "매수수량", - "offset": 20, - "start": 140 - }, - { - "fid": 8014, - "name": "매도평균가", - "offset": 20, - "start": 160 - }, - { - "fid": 8015, - "name": "매도수량", - "offset": 20, - "start": 180 - }, - { - "fid": 8017, - "name": "수수료_제세금", - "offset": 20, - "start": 200 - }, - { - "fid": 8018, - "name": "손익금액", - "offset": 20, - "start": 220 - }, - { - "fid": 8016, - "name": "매도금액", - "offset": 20, - "start": 240 - }, - { - "fid": 8013, - "name": "매수금액", - "offset": 20, - "start": 260 - }, - { - "fid": 8019, - "name": "수익률", - "offset": 20, - "start": 280 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "당일매매일지", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "400", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 8016, - "name": "총매도금액", - "offset": 20, - "start": 20 - }, - { - "fid": 8013, - "name": "총매수금액", - "offset": 20, - "start": 40 - }, - { - "fid": 8017, - "name": "총수수료_세금", - "offset": 20, - "start": 60 - }, - { - "fid": 8010, - "name": "총정산금액", - "offset": 20, - "start": 80 - }, - { - "fid": 8018, - "name": "총손익금액", - "offset": 20, - "start": 100 - }, - { - "fid": 8019, - "name": "총수익률", - "offset": 20, - "start": 120 - } - ], - "single_outputs_name": "당일매매일지단일", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt10170", - "tr_name": "SRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20001": { - "gfid": "1500", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종현재가요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간n", - "offset": 12, - "start": 0 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "전일대비기호n", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락률n", - "offset": 20, - "start": 60 - }, - { - "fid": 15, - "name": "거래량n", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "누적거래량n", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "업종현재가_시간별", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 60 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 256, - "name": "거래형성종목수", - "offset": 20, - "start": 60 - }, - { - "fid": 257, - "name": "거래형성비율", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 60 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 60 - }, - { - "fid": 251, - "name": "상한", - "offset": 20, - "start": 60 - }, - { - "fid": 252, - "name": "상승", - "offset": 20, - "start": 60 - }, - { - "fid": 253, - "name": "보합", - "offset": 20, - "start": 60 - }, - { - "fid": 255, - "name": "하락", - "offset": 20, - "start": 60 - }, - { - "fid": 254, - "name": "하한", - "offset": 20, - "start": 60 - }, - { - "fid": 1000, - "name": "52주최고가", - "offset": 20, - "start": 60 - }, - { - "fid": 1001, - "name": "52주최고가일", - "offset": 20, - "start": 60 - }, - { - "fid": 1002, - "name": "52주최고가대비율", - "offset": 20, - "start": 60 - }, - { - "fid": 1003, - "name": "52주최저가", - "offset": 20, - "start": 60 - }, - { - "fid": 1004, - "name": "52주최저가일", - "offset": 20, - "start": 60 - }, - { - "fid": 1005, - "name": "52주최저가대비율", - "offset": 20, - "start": 60 - } - ], - "single_outputs_name": "업종현재가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20001", - "tr_name": "UPJONG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20002": { - "gfid": "2016", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종별주가요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "현재거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 220 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 240 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 260 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 280 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "업종별주가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt20002", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20003": { - "gfid": "2017", - "inputs": [ - { - "fid": 9008, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "전업종지수요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 1120, - "name": "비중", - "offset": 20, - "start": 220 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 240 - }, - { - "fid": 251, - "name": "상한", - "offset": 20, - "start": 260 - }, - { - "fid": 252, - "name": "상승", - "offset": 20, - "start": 280 - }, - { - "fid": 253, - "name": "보합", - "offset": 20, - "start": 300 - }, - { - "fid": 255, - "name": "하락", - "offset": 20, - "start": 320 - }, - { - "fid": 254, - "name": "하한", - "offset": 20, - "start": 340 - }, - { - "fid": 1065, - "name": "상장종목수", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "전업종지수", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt20003", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20004": { - "gfid": "3031", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "틱범위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종틱차트조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 120 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 160 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "업종틱차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종틱차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20004", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20005": { - "gfid": "3032", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "틱범위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종분봉조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 120 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 160 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "업종분봉조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종분봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20005", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20006": { - "gfid": "3033", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종일봉조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 120 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 180 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "업종일봉조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종일봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20006", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20007": { - "gfid": "3034", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종주봉조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 120 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 180 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "업종주봉조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "300", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종주봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20007", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20008": { - "gfid": "3035", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종월봉조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 120 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 180 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "업종월봉조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "240", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종월봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20008", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20009": { - "gfid": "1502", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종현재가일별요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자n", - "offset": 12, - "start": 0 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "전일대비기호n", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락률n", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "누적거래량n", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "업종현재가_일별반복", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 60 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 60 - }, - { - "fid": 256, - "name": "거래형성종목수", - "offset": 20, - "start": 60 - }, - { - "fid": 257, - "name": "거래형성비율", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 60 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 60 - }, - { - "fid": 251, - "name": "상한", - "offset": 20, - "start": 60 - }, - { - "fid": 252, - "name": "상승", - "offset": 20, - "start": 60 - }, - { - "fid": 253, - "name": "보합", - "offset": 20, - "start": 60 - }, - { - "fid": 255, - "name": "하락", - "offset": 20, - "start": 60 - }, - { - "fid": 254, - "name": "하한", - "offset": 20, - "start": 60 - }, - { - "fid": 1000, - "name": "52주최고가", - "offset": 20, - "start": 60 - }, - { - "fid": 1001, - "name": "52주최고가일", - "offset": 20, - "start": 60 - }, - { - "fid": 1002, - "name": "52주최고가대비율", - "offset": 20, - "start": 60 - }, - { - "fid": 1003, - "name": "52주최저가", - "offset": 20, - "start": 60 - }, - { - "fid": 1004, - "name": "52주최저가일", - "offset": 20, - "start": 60 - }, - { - "fid": 1005, - "name": "52주최저가대비율", - "offset": 20, - "start": 60 - } - ], - "single_outputs_name": "업종현재가일별", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20009", - "tr_name": "UPJONG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20019": { - "gfid": "3036", - "inputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "업종년봉조회요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 120 - }, - { - "fid": 317, - "name": "대업종구분", - "offset": 20, - "start": 140 - }, - { - "fid": 318, - "name": "소업종구분", - "offset": 20, - "start": 160 - }, - { - "fid": 370, - "name": "종목정보", - "offset": 20, - "start": 180 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "업종년봉조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "업종코드", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "업종년봉차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt20019", - "tr_name": "UPCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt20068": { - "gfid": "2217", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9002, - "name": "전체구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "대차거래추이요청(종목별)", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 20 - }, - { - "fid": 312, - "name": "대차거래체결주수", - "offset": 20, - "start": 40 - }, - { - "fid": 470, - "name": "대차거래상환주수", - "offset": 20, - "start": 60 - }, - { - "fid": 476, - "name": "대차거래증감", - "offset": 20, - "start": 80 - }, - { - "fid": 471, - "name": "잔고주수", - "offset": 20, - "start": 100 - }, - { - "fid": 472, - "name": "잔고금액", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "대차거래추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt20068", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30001": { - "gfid": "2315", - "inputs": [ - { - "fid": 9020, - "name": "등락구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9021, - "name": "시간구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9013, - "name": "시간", - "offset": 20, - "start": 40 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9026, - "name": "발행사코드", - "offset": 20, - "start": 80 - }, - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 100 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 120 - }, - { - "fid": 9527, - "name": "LP코드", - "offset": 20, - "start": 140 - }, - { - "fid": 9540, - "name": "거래종료ELW제외", - "offset": 20, - "start": 160 - } - ], - "inputs_name": "ELW가격급등락요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 1027, - "name": "거래종료ELW기준가", - "offset": 20, - "start": 180 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 200 - }, - { - "fid": 1028, - "name": "기준대비", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 1037, - "name": "급등율", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "ELW가격급등락", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1041, - "name": "기준가시간", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "기준가시간", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt30001", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30002": { - "gfid": "2316", - "inputs": [ - { - "fid": 9026, - "name": "발행사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9022, - "name": "거래량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9009, - "name": "매매구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9012, - "name": "기간", - "offset": 20, - "start": 20 - }, - { - "fid": 9540, - "name": "거래종료ELW제외", - "offset": 20, - "start": 160 - } - ], - "inputs_name": "거래원별ELW순매매상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 1111, - "name": "주가등락", - "offset": 20, - "start": 120 - }, - { - "fid": 1112, - "name": "등락율", - "offset": 20, - "start": 140 - }, - { - "fid": 1113, - "name": "거래량", - "offset": 20, - "start": 160 - }, - { - "fid": 210, - "name": "순매수", - "offset": 20, - "start": 180 - }, - { - "fid": 206, - "name": "매수거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 202, - "name": "매도거래량", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "거래원별ELW순매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30002", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30003": { - "gfid": "2077", - "inputs": [ - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "ELWLP보유일별추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비구분", - "offset": 20, - "start": 0 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 0 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 0 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 0 - }, - { - "fid": 683, - "name": "변동수량", - "offset": 20, - "start": 0 - }, - { - "fid": 444, - "name": "LP보유수량", - "offset": 20, - "start": 0 - }, - { - "fid": 446, - "name": "비중", - "offset": 20, - "start": 0 - } - ], - "multi_outputs_name": "ELWLP보유일별추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30003", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30004": { - "gfid": "2036", - "inputs": [ - { - "fid": 9026, - "name": "발행사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9527, - "name": "LP코드", - "offset": 20, - "start": 60 - }, - { - "fid": 9540, - "name": "거래종료ELW제외", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "ELW괴리율요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 440, - "name": "발행사명", - "offset": 100, - "start": 0 - }, - { - "fid": 441, - "name": "회차", - "offset": 20, - "start": 0 - }, - { - "fid": 442, - "name": "기초자산명", - "offset": 20, - "start": 0 - }, - { - "fid": 443, - "name": "권리구분", - "offset": 20, - "start": 0 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 0 - }, - { - "fid": 185, - "name": "베이시스", - "offset": 20, - "start": 0 - }, - { - "fid": 445, - "name": "잔존일수", - "offset": 20, - "start": 0 - }, - { - "fid": 670, - "name": "이론가", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비구분", - "offset": 20, - "start": 0 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 0 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - } - ], - "multi_outputs_name": "ELW괴리율", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30004", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30005": { - "gfid": "2039", - "inputs": [ - { - "fid": 9026, - "name": "발행사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9527, - "name": "LP코드", - "offset": 20, - "start": 60 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "ELW조건검색요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 440, - "name": "발행사명", - "offset": 100, - "start": 20 - }, - { - "fid": 441, - "name": "회차", - "offset": 20, - "start": 120 - }, - { - "fid": 442, - "name": "기초자산명", - "offset": 100, - "start": 140 - }, - { - "fid": 443, - "name": "권리구분", - "offset": 20, - "start": 240 - }, - { - "fid": 372, - "name": "만기일", - "offset": 20, - "start": 260 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 280 - }, - { - "fid": 25, - "name": "대비구분", - "offset": 20, - "start": 300 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 320 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 340 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 360 - }, - { - "fid": 30, - "name": "거래량대비", - "offset": 20, - "start": 380 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 400 - }, - { - "fid": 304, - "name": "전일거래량", - "offset": 20, - "start": 420 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 440 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 460 - }, - { - "fid": 666, - "name": "패리티", - "offset": 20, - "start": 480 - }, - { - "fid": 667, - "name": "기어링비율", - "offset": 20, - "start": 500 - }, - { - "fid": 668, - "name": "손익분기율", - "offset": 20, - "start": 520 - }, - { - "fid": 28669, - "name": "자본지지점", - "offset": 20, - "start": 540 - }, - { - "fid": 670, - "name": "이론가", - "offset": 20, - "start": 560 - }, - { - "fid": 671, - "name": "내재변동성", - "offset": 20, - "start": 580 - }, - { - "fid": 672, - "name": "델타", - "offset": 20, - "start": 600 - }, - { - "fid": 682, - "name": "레버리지", - "offset": 20, - "start": 620 - }, - { - "fid": 425, - "name": "행사가격", - "offset": 20, - "start": 640 - }, - { - "fid": 431, - "name": "전환비율", - "offset": 20, - "start": 660 - }, - { - "fid": 446, - "name": "LP보유비율", - "offset": 20, - "start": 680 - }, - { - "fid": 683, - "name": "손익분기점", - "offset": 20, - "start": 700 - }, - { - "fid": 430, - "name": "최종거래일", - "offset": 20, - "start": 720 - }, - { - "fid": 439, - "name": "상장일", - "offset": 20, - "start": 740 - }, - { - "fid": 447, - "name": "LP초종공급일", - "offset": 20, - "start": 760 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 780 - }, - { - "fid": 445, - "name": "잔존일수", - "offset": 20, - "start": 880 - }, - { - "fid": 686, - "name": "괴리율", - "offset": 20, - "start": 900 - }, - { - "fid": 661, - "name": "LP회원사명", - "offset": 100, - "start": 920 - }, - { - "fid": 691, - "name": "LP회원사명1", - "offset": 20, - "start": 1020 - }, - { - "fid": 689, - "name": "LP회원사명2", - "offset": 20, - "start": 1040 - }, - { - "fid": 704, - "name": "Xray순간체결량정리매매구분", - "offset": 20, - "start": 1060 - }, - { - "fid": 706, - "name": "Xray순간체결량증거금100구분", - "offset": 20, - "start": 1080 - } - ], - "multi_outputs_name": "ELW조건검색", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30005", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30006": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ELW종목상세요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 670, - "name": "이론가", - "offset": 20, - "start": 20 - }, - { - "fid": 686, - "name": "괴리율", - "offset": 20, - "start": 40 - }, - { - "fid": 671, - "name": "내재변동성", - "offset": 20, - "start": 60 - }, - { - "fid": 668, - "name": "손익분기율", - "offset": 20, - "start": 100 - }, - { - "fid": 425, - "name": "행사가격", - "offset": 20, - "start": 120 - }, - { - "fid": 431, - "name": "전환비율", - "offset": 20, - "start": 140 - }, - { - "fid": 433, - "name": "보상율", - "offset": 20, - "start": 160 - }, - { - "fid": 432, - "name": "가격상승참여율", - "offset": 20, - "start": 180 - }, - { - "fid": 426, - "name": "권리유형", - "offset": 20, - "start": 200 - }, - { - "fid": 445, - "name": "잔존일수", - "offset": 20, - "start": 220 - }, - { - "fid": 312, - "name": "주식수", - "offset": 20, - "start": 240 - }, - { - "fid": 446, - "name": "LP보유비율", - "offset": 20, - "start": 280 - }, - { - "fid": 444, - "name": "LP보유수량", - "offset": 20, - "start": 300 - }, - { - "fid": 412, - "name": "스프레드", - "offset": 20, - "start": 320 - }, - { - "fid": 666, - "name": "패리티", - "offset": 20, - "start": 340 - }, - { - "fid": 667, - "name": "기어링비율", - "offset": 20, - "start": 360 - }, - { - "fid": 439, - "name": "상장일", - "offset": 20, - "start": 380 - }, - { - "fid": 430, - "name": "최종거래일", - "offset": 20, - "start": 400 - }, - { - "fid": 372, - "name": "신주인수권행사종료일", - "offset": 20, - "start": 420 - }, - { - "fid": 371, - "name": "신주인수권행사게시일", - "offset": 20, - "start": 440 - }, - { - "fid": 447, - "name": "LP최종공급일", - "offset": 20, - "start": 460 - }, - { - "fid": 434, - "name": "지급일", - "offset": 20, - "start": 480 - }, - { - "fid": 437, - "name": "투자지표산출여부", - "offset": 20, - "start": 500 - }, - { - "fid": 435, - "name": "지급대리인", - "offset": 100, - "start": 520 - }, - { - "fid": 429, - "name": "결제방법", - "offset": 100, - "start": 620 - }, - { - "fid": 427, - "name": "권리행사방식", - "offset": 20, - "start": 720 - }, - { - "fid": 413, - "name": "한글발행기관명", - "offset": 100, - "start": 740 - }, - { - "fid": 448, - "name": "확정지급금액", - "offset": 20, - "start": 760 - }, - { - "fid": 690, - "name": "KO베리어", - "offset": 20, - "start": 780 - }, - { - "fid": 706, - "name": "XRay순간체결량증거금100%구분", - "offset": 20, - "start": 800 - } - ], - "single_outputs_name": "ELW종목상세2", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt30006", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30007": { - "gfid": "2036", - "inputs": [ - { - "fid": 9026, - "name": "발행사코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9527, - "name": "LP코드", - "offset": 20, - "start": 60 - }, - { - "fid": 9009, - "name": "정렬구분", - "offset": 20, - "start": 80 - }, - { - "fid": 9540, - "name": "거래종료ELW제외", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "ELW종목상세요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "기초자산코드", - "offset": 20, - "start": 0 - }, - { - "fid": 440, - "name": "발행사명", - "offset": 100, - "start": 20 - }, - { - "fid": 441, - "name": "회차", - "offset": 20, - "start": 120 - }, - { - "fid": 442, - "name": "기초자산명", - "offset": 100, - "start": 140 - }, - { - "fid": 443, - "name": "콜풋구분", - "offset": 20, - "start": 240 - }, - { - "fid": 372, - "name": "신주인수권행사종료일", - "offset": 20, - "start": 260 - }, - { - "fid": 445, - "name": "잔존일수", - "offset": 20, - "start": 280 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 300 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 320 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 340 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 360 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 380 - }, - { - "fid": 30, - "name": "거래량대비", - "offset": 20, - "start": 400 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 420 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 440 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 460 - }, - { - "fid": 666, - "name": "패리티", - "offset": 20, - "start": 480 - }, - { - "fid": 667, - "name": "기어링비율", - "offset": 20, - "start": 500 - }, - { - "fid": 668, - "name": "손익분기율", - "offset": 20, - "start": 520 - }, - { - "fid": 669, - "name": "자본지지점", - "offset": 20, - "start": 540 - }, - { - "fid": 670, - "name": "이론가", - "offset": 20, - "start": 560 - }, - { - "fid": 671, - "name": "내재변동성", - "offset": 20, - "start": 580 - }, - { - "fid": 672, - "name": "델타", - "offset": 20, - "start": 600 - }, - { - "fid": 682, - "name": "레버리지", - "offset": 20, - "start": 620 - }, - { - "fid": 446, - "name": "LP보유비율", - "offset": 20, - "start": 640 - }, - { - "fid": 425, - "name": "행사가격", - "offset": 20, - "start": 660 - }, - { - "fid": 431, - "name": "전환비율", - "offset": 20, - "start": 680 - }, - { - "fid": 430, - "name": "최종거래일", - "offset": 20, - "start": 700 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 720 - }, - { - "fid": 689, - "name": "조기종료여부", - "offset": 20, - "start": 820 - }, - { - "fid": 691, - "name": "KO접근도", - "offset": 20, - "start": 840 - } - ], - "multi_outputs_name": "ELW종목상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30007", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30008": { - "gfid": "2038", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "ELW민감도지표요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 671, - "name": "내재변동성", - "offset": 20, - "start": 20 - }, - { - "fid": 672, - "name": "델타", - "offset": 20, - "start": 40 - }, - { - "fid": 673, - "name": "감마", - "offset": 20, - "start": 60 - }, - { - "fid": 674, - "name": "쎄타", - "offset": 20, - "start": 80 - }, - { - "fid": 675, - "name": "베가", - "offset": 20, - "start": 100 - }, - { - "fid": 676, - "name": "로", - "offset": 20, - "start": 120 - }, - { - "fid": 706, - "name": "X-Ray순간체결량증거금100%구분", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "ELW민감도지표", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30008", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30009": { - "gfid": "2029", - "inputs": [ - { - "fid": 9009, - "name": "정렬구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9540, - "name": "거래종료제외", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "ELW등락율순위요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 0 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 180 - }, - { - "fid": 121, - "name": "매도잔량", - "offset": 20, - "start": 200 - }, - { - "fid": 125, - "name": "매수잔량", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "ELW등락율순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30009", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30010": { - "gfid": "2035", - "inputs": [ - { - "fid": 9009, - "name": "정렬구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9040, - "name": "권리구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9540, - "name": "거래종료제외", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "ELW잔량순위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 121, - "name": "매도잔량", - "offset": 20, - "start": 240 - }, - { - "fid": 125, - "name": "매수잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "ELW잔량순위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30010", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30011": { - "gfid": "2212", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ELW근접율요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 20, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 80 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 9019, - "name": "근접율", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "ELW근접율", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt30011", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt30012": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ELW종목상세정보요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 395, - "name": "자산코드", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 9, - "start": 20 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 1, - "start": 29 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 9, - "start": 2060 - }, - { - "fid": 12, - "name": "등락율", - "offset": 9, - "start": 2060 - }, - { - "fid": 664, - "name": "LP회원사명", - "offset": 20, - "start": 3180 - }, - { - "fid": 661, - "name": "LP회원사명1", - "offset": 20, - "start": 3160 - }, - { - "fid": 662, - "name": "LP회원사명2", - "offset": 20, - "start": 3200 - }, - { - "fid": 428, - "name": "ELW권리내용", - "offset": 100, - "start": 1020 - }, - { - "fid": 436, - "name": "ELW만기평가가격", - "offset": 100, - "start": 1040 - }, - { - "fid": 670, - "name": "ELW이론가", - "offset": 10, - "start": 20 - }, - { - "fid": 686, - "name": "괴리율", - "offset": 10, - "start": 40 - }, - { - "fid": 671, - "name": "ELW내재변동성", - "offset": 10, - "start": 60 - }, - { - "fid": 687, - "name": "예상권리가", - "offset": 20, - "start": 100 - }, - { - "fid": 668, - "name": "ELW손익분기율", - "offset": 10, - "start": 100 - }, - { - "fid": 425, - "name": "ELW행사가", - "offset": 20, - "start": 120 - }, - { - "fid": 431, - "name": "ELW전환비율", - "offset": 20, - "start": 140 - }, - { - "fid": 433, - "name": "ELW보상율", - "offset": 10, - "start": 160 - }, - { - "fid": 432, - "name": "ELW가격상승참여율", - "offset": 10, - "start": 180 - }, - { - "fid": 426, - "name": "ELW권리유형", - "offset": 10, - "start": 200 - }, - { - "fid": 445, - "name": "ELW잔존일수", - "offset": 10, - "start": 220 - }, - { - "fid": 312, - "name": "주식수", - "offset": 20, - "start": 240 - }, - { - "fid": 438, - "name": "ELW LP주문가능", - "offset": 10, - "start": 280 - }, - { - "fid": 446, - "name": "LP보유비율", - "offset": 20, - "start": 280 - }, - { - "fid": 444, - "name": "LP보유수량", - "offset": 20, - "start": 300 - }, - { - "fid": 412, - "name": "ELW스프레드", - "offset": 10, - "start": 320 - }, - { - "fid": 666, - "name": "ELW패리티", - "offset": 10, - "start": 340 - }, - { - "fid": 667, - "name": "ELW기어링", - "offset": 10, - "start": 360 - }, - { - "fid": 439, - "name": "ELW상장일", - "offset": 10, - "start": 380 - }, - { - "fid": 430, - "name": "ELW최종거래일", - "offset": 10, - "start": 400 - }, - { - "fid": 372, - "name": "만기일", - "offset": 10, - "start": 420 - }, - { - "fid": 371, - "name": "행사일", - "offset": 10, - "start": 440 - }, - { - "fid": 447, - "name": "LP공급종료일", - "offset": 20, - "start": 460 - }, - { - "fid": 434, - "name": "ELW지급일", - "offset": 10, - "start": 480 - }, - { - "fid": 437, - "name": "ELW투자지표산출", - "offset": 10, - "start": 500 - }, - { - "fid": 435, - "name": "ELW지급대리인", - "offset": 20, - "start": 520 - }, - { - "fid": 429, - "name": "ELW결재방법", - "offset": 20, - "start": 620 - }, - { - "fid": 427, - "name": "ELW권리행사방식", - "offset": 10, - "start": 720 - }, - { - "fid": 413, - "name": "ELW발행기관", - "offset": 20, - "start": 740 - }, - { - "fid": 448, - "name": "확정지급액", - "offset": 20, - "start": 760 - }, - { - "fid": 690, - "name": "KO베리어", - "offset": 20, - "start": 780 - }, - { - "fid": 709, - "name": "IV", - "offset": 20, - "start": 780 - }, - { - "fid": 689, - "name": "종기종료ELW발생", - "offset": 20, - "start": 0 - }, - { - "fid": 414, - "name": "기초자산1", - "offset": 20, - "start": 820 - }, - { - "fid": 419, - "name": "기초자산구성비율1", - "offset": 6, - "start": 840 - }, - { - "fid": 415, - "name": "기초자산2", - "offset": 20, - "start": 860 - }, - { - "fid": 420, - "name": "기초자산구성비율2", - "offset": 6, - "start": 880 - }, - { - "fid": 416, - "name": "기초자산3", - "offset": 20, - "start": 900 - }, - { - "fid": 421, - "name": "기초자산구성비율3", - "offset": 6, - "start": 920 - }, - { - "fid": 417, - "name": "기초자산4", - "offset": 20, - "start": 940 - }, - { - "fid": 422, - "name": "기초자산구성비율4", - "offset": 6, - "start": 960 - }, - { - "fid": 418, - "name": "기초자산5", - "offset": 20, - "start": 980 - }, - { - "fid": 423, - "name": "기초자산구성비율5", - "offset": 6, - "start": 1000 - }, - { - "fid": 692, - "name": "평가시작일자", - "offset": 20, - "start": 3220 - }, - { - "fid": 694, - "name": "평가종료일자", - "offset": 20, - "start": 3240 - }, - { - "fid": 693, - "name": "평가시작시간", - "offset": 20, - "start": 3300 - }, - { - "fid": 695, - "name": "평가종료시간", - "offset": 20, - "start": 3320 - }, - { - "fid": 696, - "name": "평가가격", - "offset": 20, - "start": 3260 - }, - { - "fid": 697, - "name": "평가완료여부", - "offset": 20, - "start": 3280 - }, - { - "fid": 698, - "name": "전체최고가", - "offset": 20, - "start": 3340 - }, - { - "fid": 699, - "name": "전체최저가", - "offset": 20, - "start": 3360 - }, - { - "fid": 710, - "name": "직후최고가", - "offset": 20, - "start": 3340 - }, - { - "fid": 711, - "name": "직후최저가", - "offset": 20, - "start": 3360 - }, - { - "fid": 712, - "name": "후반장최고가", - "offset": 20, - "start": 3340 - }, - { - "fid": 713, - "name": "후반장최저가", - "offset": 20, - "start": 3360 - } - ], - "single_outputs_name": "ELW종목상세정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt30012", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40001": { - "gfid": "2448", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 6, - "start": 0 - }, - { - "fid": 9700, - "name": "모름", - "offset": 6, - "start": 0 - }, - { - "fid": 9305, - "name": "기간", - "offset": 6, - "start": 0 - } - ], - "inputs_name": "ETF수익율요청", - "multi_outputs": [ - { - "fid": 221, - "name": "ETF수익률", - "offset": 20, - "start": 0 - }, - { - "fid": 220, - "name": "체결수익률", - "offset": 20, - "start": 20 - }, - { - "fid": 1137, - "name": "외인순매수수량", - "offset": 20, - "start": 40 - }, - { - "fid": 1136, - "name": "기관순매수수량", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "ETF수익율", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "1", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40001", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40002": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF종목정보요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 1094, - "name": "ETF대상지수명", - "offset": 100, - "start": 0 - }, - { - "fid": 1341, - "name": "원주가격", - "offset": 20, - "start": 0 - }, - { - "fid": 1342, - "name": "ETF과세유형", - "offset": 20, - "start": 0 - }, - { - "fid": 1396, - "name": "ETN과세유형", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "ETF종목정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt40002", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40003": { - "gfid": "1509", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF일별추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "체결일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 36, - "name": "NAV", - "offset": 20, - "start": 120 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 140 - }, - { - "fid": 265, - "name": "NAV/지수괴리율", - "offset": 20, - "start": 160 - }, - { - "fid": 266, - "name": "NAV/ETF괴리율", - "offset": 20, - "start": 180 - }, - { - "fid": 39, - "name": "추적오차율", - "offset": 20, - "start": 200 - }, - { - "fid": 768, - "name": "추적현재가", - "offset": 20, - "start": 220 - }, - { - "fid": 769, - "name": "추적전일대비", - "offset": 20, - "start": 240 - }, - { - "fid": 770, - "name": "추적대비기호", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "ETF일별추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40003", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40004": { - "gfid": "2024", - "inputs": [ - { - "fid": 9132, - "name": "과세유형", - "offset": 20, - "start": 0 - }, - { - "fid": 9131, - "name": "NAV대비", - "offset": 20, - "start": 20 - }, - { - "fid": 9133, - "name": "운용사", - "offset": 20, - "start": 40 - }, - { - "fid": 9137, - "name": "과세여부", - "offset": 20, - "start": 60 - }, - { - "fid": 9130, - "name": "추적지수", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "ETF전체시세요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 300, - "name": "종목분류", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 40 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 240 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 260 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 320 - }, - { - "fid": 36, - "name": "NAV", - "offset": 20, - "start": 340 - }, - { - "fid": 39, - "name": "추적오차율", - "offset": 20, - "start": 360 - }, - { - "fid": 1085, - "name": "과표기준", - "offset": 20, - "start": 380 - }, - { - "fid": 1087, - "name": "배당전기준", - "offset": 20, - "start": 400 - }, - { - "fid": 1086, - "name": "전일배당금", - "offset": 20, - "start": 420 - }, - { - "fid": 1094, - "name": "추적지수명", - "offset": 200, - "start": 440 - }, - { - "fid": 1088, - "name": "배수", - "offset": 20, - "start": 640 - }, - { - "fid": 1086, - "name": "추적지수코드", - "offset": 20, - "start": 660 - }, - { - "fid": 10, - "name": "추적지수", - "offset": 20, - "start": 680 - }, - { - "fid": 12, - "name": "추적등락율", - "offset": 20, - "start": 760 - } - ], - "multi_outputs_name": "ETF전체시세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40004", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40005": { - "gfid": "1509", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF일별추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "대비율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 36, - "name": "NAV", - "offset": 20, - "start": 120 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 140 - }, - { - "fid": 265, - "name": "NAV/지수괴리율", - "offset": 20, - "start": 160 - }, - { - "fid": 266, - "name": "NAV/ETF괴리율", - "offset": 20, - "start": 180 - }, - { - "fid": 39, - "name": "추적오차율", - "offset": 20, - "start": 200 - }, - { - "fid": 768, - "name": "추적지수", - "offset": 20, - "start": 220 - }, - { - "fid": 770, - "name": "추적대비기호", - "offset": 20, - "start": 240 - }, - { - "fid": 769, - "name": "추적전일대비", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "ETF일별추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40005", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40006": { - "gfid": "1508", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF시간대별추이요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 200, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 240 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 320 - }, - { - "fid": 36, - "name": "NAV", - "offset": 20, - "start": 340 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 660 - }, - { - "fid": 265, - "name": "NAV지수", - "offset": 20, - "start": 660 - }, - { - "fid": 266, - "name": "NAVETF", - "offset": 20, - "start": 360 - }, - { - "fid": 39, - "name": "추적", - "offset": 20, - "start": 380 - }, - { - "fid": 768, - "name": "추적지수", - "offset": 20, - "start": 400 - }, - { - "fid": 769, - "name": "추적지수전일대비", - "offset": 20, - "start": 420 - }, - { - "fid": 770, - "name": "추적지수전일대비기호", - "offset": 200, - "start": 440 - } - ], - "multi_outputs_name": "ETF시간대별추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 1094, - "name": "ETF대상지수명", - "offset": 100, - "start": 0 - }, - { - "fid": 1341, - "name": "원주가격", - "offset": 20, - "start": 0 - }, - { - "fid": 1342, - "name": "ETF과세유형", - "offset": 20, - "start": 0 - }, - { - "fid": 1396, - "name": "ETN과세유형", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "ETF종목정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt40006", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40007": { - "gfid": "1500", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF시간대별체결요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 80 - } - ], - "multi_outputs_name": "ETF시간대별체결배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 300, - "name": "종목분류", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 1094, - "name": "ETF대상지수명", - "offset": 100, - "start": 120 - }, - { - "fid": 1093, - "name": "ETF대상지수코드", - "offset": 20, - "start": 220 - }, - { - "fid": 375, - "name": "대상지수대비율", - "offset": 20, - "start": 240 - }, - { - "fid": 1341, - "name": "원주가격", - "offset": 20, - "start": 260 - } - ], - "single_outputs_name": "ETF시간대별체결", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt40007", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40008": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF일자별체결요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호n", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 80 - }, - { - "fid": 1137, - "name": "외인순매수수량", - "offset": 20, - "start": 100 - }, - { - "fid": 1136, - "name": "기관순매수수량", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "ETF순매수수량배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 80 - } - ], - "single_outputs_name": "ETF일자별체결", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt40008", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40009": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF시간대별체결요청", - "multi_outputs": [ - { - "fid": 36, - "name": "NAV", - "offset": 20, - "start": 0 - }, - { - "fid": 37, - "name": "NAV전일대비", - "offset": 20, - "start": 20 - }, - { - "fid": 38, - "name": "NAV등락율", - "offset": 20, - "start": 40 - }, - { - "fid": 39, - "name": "추적오차율", - "offset": 20, - "start": 60 - }, - { - "fid": 40, - "name": "괴리율", - "offset": 20, - "start": 80 - }, - { - "fid": 312, - "name": "주식수", - "offset": 20, - "start": 100 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 120 - }, - { - "fid": 313, - "name": "외인보유수량", - "offset": 20, - "start": 140 - }, - { - "fid": 308, - "name": "대용가", - "offset": 20, - "start": 160 - }, - { - "fid": 1085, - "name": "모름", - "offset": 20, - "start": 180 - }, - { - "fid": 1087, - "name": "환산가격", - "offset": 20, - "start": 200 - }, - { - "fid": 1086, - "name": "DR/주", - "offset": 20, - "start": 220 - }, - { - "fid": 1089, - "name": "원주가격", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "ETFNAV배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40009", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt40010": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "ETF시간대별추이요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 60 - }, - { - "fid": 1137, - "name": "외인순매수", - "offset": 20, - "start": 80 - } - ], - "multi_outputs_name": "ETF시간대별추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt40010", - "tr_name": "STOCK", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50001": { - "gfid": "1500", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵현재가정보요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호n", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 60 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 80 - }, - { - "fid": 195, - "name": "미결제약정n", - "offset": 20, - "start": 100 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 120 - }, - { - "fid": 183, - "name": "시장베이시스n", - "offset": 20, - "start": 140 - }, - { - "fid": 327, - "name": "역사적변동성", - "offset": 20, - "start": 160 - }, - { - "fid": 338, - "name": "표면이자", - "offset": 20, - "start": 180 - }, - { - "fid": 361, - "name": "배당액지수", - "offset": 20, - "start": 200 - }, - { - "fid": 307, - "name": "기준가n", - "offset": 20, - "start": 220 - }, - { - "fid": 12, - "name": "등락율n", - "offset": 20, - "start": 240 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "선옵시간대별체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 60 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 80 - }, - { - "fid": 30, - "name": "거래량대비", - "offset": 20, - "start": 100 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 120 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 140 - }, - { - "fid": 184, - "name": "이론베이시스", - "offset": 20, - "start": 160 - }, - { - "fid": 185, - "name": "괴리도", - "offset": 20, - "start": 180 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 200 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 220 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 240 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 260 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 280 - }, - { - "fid": 320, - "name": "CB상한가", - "offset": 20, - "start": 300 - }, - { - "fid": 321, - "name": "CB하한가", - "offset": 20, - "start": 320 - }, - { - "fid": 338, - "name": "대용가", - "offset": 20, - "start": 340 - }, - { - "fid": 322, - "name": "최종거래일", - "offset": 20, - "start": 360 - }, - { - "fid": 323, - "name": "잔존일수", - "offset": 20, - "start": 380 - }, - { - "fid": 403, - "name": "영업일기준잔존일", - "offset": 20, - "start": 400 - }, - { - "fid": 1018, - "name": "상장중최고가", - "offset": 20, - "start": 420 - }, - { - "fid": 1020, - "name": "상장중최고가대비율", - "offset": 20, - "start": 440 - }, - { - "fid": 1019, - "name": "상장중최고가일", - "offset": 20, - "start": 460 - }, - { - "fid": 1021, - "name": "상장중최저가", - "offset": 20, - "start": 480 - }, - { - "fid": 1023, - "name": "상장중최저가대비율", - "offset": 20, - "start": 500 - }, - { - "fid": 1022, - "name": "상장중최저가일", - "offset": 20, - "start": 520 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 540 - }, - { - "fid": 21, - "name": "호가시간", - "offset": 20, - "start": 640 - }, - { - "fid": 85, - "name": "매도수익율5", - "offset": 20, - "start": 660 - }, - { - "fid": 105, - "name": "매도건수5", - "offset": 20, - "start": 680 - }, - { - "fid": 65, - "name": "매도수량5", - "offset": 20, - "start": 700 - }, - { - "fid": 84, - "name": "매도수익율4", - "offset": 20, - "start": 720 - }, - { - "fid": 104, - "name": "매도건수4", - "offset": 20, - "start": 740 - }, - { - "fid": 64, - "name": "매도수량4", - "offset": 20, - "start": 760 - }, - { - "fid": 44, - "name": "매도호가4", - "offset": 20, - "start": 780 - }, - { - "fid": 45, - "name": "매도호가5", - "offset": 20, - "start": 800 - }, - { - "fid": 83, - "name": "매도수익율3", - "offset": 20, - "start": 820 - }, - { - "fid": 103, - "name": "매도건수3", - "offset": 20, - "start": 840 - }, - { - "fid": 63, - "name": "매도수량3", - "offset": 20, - "start": 860 - }, - { - "fid": 43, - "name": "매도호가3", - "offset": 20, - "start": 880 - }, - { - "fid": 82, - "name": "매도수익율2", - "offset": 20, - "start": 900 - }, - { - "fid": 102, - "name": "매도건수2", - "offset": 20, - "start": 920 - }, - { - "fid": 62, - "name": "매도수량2", - "offset": 20, - "start": 940 - }, - { - "fid": 42, - "name": "매도호가2", - "offset": 20, - "start": 960 - }, - { - "fid": 81, - "name": "매도수익율1", - "offset": 20, - "start": 980 - }, - { - "fid": 101, - "name": "매도건수1", - "offset": 20, - "start": 1000 - }, - { - "fid": 61, - "name": "매도수량1", - "offset": 20, - "start": 1020 - }, - { - "fid": 41, - "name": "매도호가1", - "offset": 20, - "start": 1040 - }, - { - "fid": 51, - "name": "매수호가1", - "offset": 20, - "start": 1060 - }, - { - "fid": 71, - "name": "매수수량1", - "offset": 20, - "start": 1080 - }, - { - "fid": 111, - "name": "매수건수1", - "offset": 20, - "start": 1100 - }, - { - "fid": 91, - "name": "매수수익율1", - "offset": 20, - "start": 1120 - }, - { - "fid": 52, - "name": "매수호가2", - "offset": 20, - "start": 1140 - }, - { - "fid": 72, - "name": "매수수량2", - "offset": 20, - "start": 1160 - }, - { - "fid": 112, - "name": "매수건수2", - "offset": 20, - "start": 1180 - }, - { - "fid": 92, - "name": "매수수익율2", - "offset": 20, - "start": 1200 - }, - { - "fid": 53, - "name": "매수호가3", - "offset": 20, - "start": 1220 - }, - { - "fid": 73, - "name": "매수수량3", - "offset": 20, - "start": 1240 - }, - { - "fid": 113, - "name": "매수건수3", - "offset": 20, - "start": 1260 - }, - { - "fid": 93, - "name": "매수수익율3", - "offset": 20, - "start": 1280 - }, - { - "fid": 54, - "name": "매수호가4", - "offset": 20, - "start": 1300 - }, - { - "fid": 74, - "name": "매수수량4", - "offset": 20, - "start": 1320 - }, - { - "fid": 114, - "name": "매수건수4", - "offset": 20, - "start": 1340 - }, - { - "fid": 94, - "name": "매수수익율4", - "offset": 20, - "start": 1360 - }, - { - "fid": 55, - "name": "매수호가5", - "offset": 20, - "start": 1380 - }, - { - "fid": 75, - "name": "매수수량5", - "offset": 20, - "start": 1400 - }, - { - "fid": 115, - "name": "매수건수5", - "offset": 20, - "start": 1420 - }, - { - "fid": 95, - "name": "매수수익율5", - "offset": 20, - "start": 1440 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 1460 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 1480 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 1500 - }, - { - "fid": 341, - "name": "2차저항", - "offset": 20, - "start": 1520 - }, - { - "fid": 340, - "name": "1차저항", - "offset": 20, - "start": 1540 - }, - { - "fid": 339, - "name": "피봇", - "offset": 20, - "start": 1560 - }, - { - "fid": 342, - "name": "1차저지", - "offset": 20, - "start": 1580 - }, - { - "fid": 343, - "name": "2차저지", - "offset": 20, - "start": 1600 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 1620 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 1640 - }, - { - "fid": 123, - "name": "매도호가총건수", - "offset": 20, - "start": 1660 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 1680 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 1700 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 1720 - }, - { - "fid": 127, - "name": "매수호가총건수", - "offset": 20, - "start": 1740 - }, - { - "fid": 122, - "name": "매도호가총잔량직전대비", - "offset": 20, - "start": 1760 - }, - { - "fid": 126, - "name": "매수호가총잔량직전대비", - "offset": 20, - "start": 1780 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 1800 - }, - { - "fid": 238, - "name": "예상체결가전일종가대비기호", - "offset": 20, - "start": 1820 - }, - { - "fid": 200, - "name": "예상체결가전일종가대비", - "offset": 20, - "start": 1840 - }, - { - "fid": 201, - "name": "예상체결가전일종가대비등락율", - "offset": 20, - "start": 1860 - }, - { - "fid": 338, - "name": "이자율", - "offset": 20, - "start": 1880 - } - ], - "single_outputs_name": "선옵현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50001", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50002": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵일자별체결요청", - "multi_outputs": [ - { - "fid": 22, - "name": "체결일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호n", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율n", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 120 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 140 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 160 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 180 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 200 - }, - { - "fid": 238, - "name": "예상체결가전일종가대비기호", - "offset": 20, - "start": 220 - }, - { - "fid": 200, - "name": "예상체결가전일종가대비", - "offset": 20, - "start": 240 - }, - { - "fid": 201, - "name": "예상체결가전일종가대비등락율", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "선옵일자별체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 200 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 220 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 240 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 260 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 280 - } - ], - "single_outputs_name": "선옵종목명", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50002", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50003": { - "gfid": "1505", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵시고저가요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 40 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 80 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 100 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 120 - }, - { - "fid": 246, - "name": "시초미결제약정수량", - "offset": 20, - "start": 140 - }, - { - "fid": 247, - "name": "최고미결제약정수량", - "offset": 20, - "start": 160 - }, - { - "fid": 248, - "name": "최저미결제약정수량", - "offset": 20, - "start": 180 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 200 - }, - { - "fid": 269, - "name": "전일미결제약정", - "offset": 20, - "start": 220 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 240 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 260 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 280 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 300 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 320 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 340 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 360 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 380 - } - ], - "single_outputs_name": "선옵시고저가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50003", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50004": { - "gfid": "2102", - "inputs": [ - { - "fid": 9100, - "name": "만기년월", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "콜옵션행사가요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 20 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 40 - } - ], - "multi_outputs_name": "콜옵션행사가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50004", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50005": { - "gfid": "1506", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵시간별거래량요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 20 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "선옵시간별거래량", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50005", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50006": { - "gfid": "1506", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵체결추이요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 120 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 140 - }, - { - "fid": 30, - "name": "전일거래량대비", - "offset": 20, - "start": 160 - }, - { - "fid": 304, - "name": "전일거래량", - "offset": 20, - "start": 180 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "선옵체결추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 0 - } - ], - "single_outputs_name": "선옵종목명", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50006", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50007": { - "gfid": "1501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - }, - { - "fid": 9002, - "name": "시간검색", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "선물시세추이요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 16, - "name": "시가n", - "offset": 20, - "start": 20 - }, - { - "fid": 17, - "name": "고가n", - "offset": 20, - "start": 40 - }, - { - "fid": 18, - "name": "저가n", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 80 - }, - { - "fid": 25, - "name": "대비기호n", - "offset": 20, - "start": 100 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 120 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 140 - }, - { - "fid": 13, - "name": "누적거래량n", - "offset": 20, - "start": 160 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 180 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 200 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 220 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 240 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 260 - }, - { - "fid": 187, - "name": "내재가치n", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "선물시세추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 80 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 100 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 120 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 140 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 160 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 180 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 200 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 220 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 240 - } - ], - "single_outputs_name": "선물현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50007", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50008": { - "gfid": "2354", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9038, - "name": "시간구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "프로그램매매추이차트요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 204, - "name": "투자자별매도금액", - "offset": 20, - "start": 20 - }, - { - "fid": 208, - "name": "투자자별매수금액", - "offset": 20, - "start": 40 - }, - { - "fid": 212, - "name": "투자자별순매수금액", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "투자자별매도수금액", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50008", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50009": { - "gfid": "1504", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9002, - "name": "시간검색", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵시간별잔량요청", - "multi_outputs": [ - { - "fid": 21, - "name": "호가시간", - "offset": 20, - "start": 0 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 20 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 40 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "선옵시간별잔량", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 0 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 20 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 40 - } - ], - "single_outputs_name": "선옵시고저가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50009", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50010": { - "gfid": "1504", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9002, - "name": "시간검색", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵호가잔량추이요청", - "multi_outputs": [ - { - "fid": 21, - "name": "호가시간", - "offset": 20, - "start": 0 - }, - { - "fid": 61, - "name": "매도호가수량", - "offset": 20, - "start": 20 - }, - { - "fid": 27, - "name": "최우선매도호가", - "offset": 20, - "start": 40 - }, - { - "fid": 71, - "name": "매수호가수량", - "offset": 20, - "start": 60 - }, - { - "fid": 28, - "name": "최우선매수호가", - "offset": 20, - "start": 80 - }, - { - "fid": 137, - "name": "호가순잔량", - "offset": 20, - "start": 100 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 120 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 140 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "선옵호가잔량추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 0 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 20 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 40 - } - ], - "single_outputs_name": "선옵시고저가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50010", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50011": { - "gfid": "1504", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - }, - { - "fid": 9002, - "name": "시간검색", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "선옵호가잔량추이요청", - "multi_outputs": [ - { - "fid": 21, - "name": "호가시간", - "offset": 20, - "start": 0 - }, - { - "fid": 61, - "name": "매도호가수량", - "offset": 20, - "start": 20 - }, - { - "fid": 27, - "name": "최우선매도호가", - "offset": 20, - "start": 40 - }, - { - "fid": 71, - "name": "매수호가수량", - "offset": 20, - "start": 60 - }, - { - "fid": 28, - "name": "최우선매수호가", - "offset": 20, - "start": 80 - }, - { - "fid": 137, - "name": "호가순잔량", - "offset": 20, - "start": 100 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 120 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 140 - }, - { - "fid": 128, - "name": "순매수잔량", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "선옵호가잔량추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50011", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50012": { - "gfid": "3012", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵타임스프레드차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - } - ], - "multi_outputs_name": "선옵타임스프레드차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50012", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50013": { - "gfid": "1501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9045, - "name": "봉갯수", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물가격대별비중차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - } - ], - "multi_outputs_name": "선물가격대별비중차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50013", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50014": { - "gfid": "1503", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9045, - "name": "봉갯수", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물가격대별비중차트요청", - "multi_outputs": [ - { - "fid": 1080, - "name": "구간구분", - "offset": 200, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 1029, - "name": "비중", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "선물가격대별비중차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 120 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 140 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 160 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 180 - } - ], - "single_outputs_name": "선물현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50014", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50015": { - "gfid": "3013", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물미결제약정일차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 22, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 40 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "선물미결제약정일차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가s", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호s", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비s", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율s", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가s", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가s", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량s", - "offset": 20, - "start": 120 - }, - { - "fid": 195, - "name": "미결제약정s", - "offset": 20, - "start": 140 - }, - { - "fid": 302, - "name": "종목명s", - "offset": 200, - "start": 160 - } - ], - "single_outputs_name": "선물현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50015", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50016": { - "gfid": "1501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "베이시스추이차트요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 80 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 100 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 120 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 140 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 160 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "베이시스추이차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "800", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "전일종가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50016", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50017": { - "gfid": "1501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "베이시스추이차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 40 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 80 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 100 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 120 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "베이시스추이차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "800", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50017", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50018": { - "gfid": "2105", - "inputs": [ - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "풋콜옵션비율차트요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 379, - "name": "콜풋RATIO", - "offset": 20, - "start": 20 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 40 - } - ], - "multi_outputs_name": "풋콜옵션비율차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "400", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50018", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50019": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선물옵션현재가정보요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 200 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 220 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 240 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 260 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 280 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 300 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 320 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 340 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 360 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 380 - }, - { - "fid": 26, - "name": "거래량전일대비", - "offset": 20, - "start": 400 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 420 - }, - { - "fid": 29, - "name": "거래대금증감", - "offset": 20, - "start": 440 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 460 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 480 - }, - { - "fid": 327, - "name": "역사적변동성", - "offset": 20, - "start": 500 - }, - { - "fid": 338, - "name": "표면이자", - "offset": 20, - "start": 520 - }, - { - "fid": 361, - "name": "배당액지수", - "offset": 20, - "start": 540 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 560 - }, - { - "fid": 61, - "name": "매도수량", - "offset": 20, - "start": 580 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 600 - }, - { - "fid": 71, - "name": "매수수량", - "offset": 20, - "start": 620 - } - ], - "single_outputs_name": "선물옵션현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50019", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50020": { - "gfid": "2101", - "inputs": [ - { - "fid": 9100, - "name": "만기년월", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "복수종목결제월별시세요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 20 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 80 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 100 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 120 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 140 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 160 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 200 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 71, - "name": "매수호가수량", - "offset": 20, - "start": 300 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 320 - }, - { - "fid": 61, - "name": "매도호가수량", - "offset": 20, - "start": 340 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 360 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 380 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 400 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 420 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 440 - }, - { - "fid": 391, - "name": "기준가대비시가등락율", - "offset": 20, - "start": 460 - }, - { - "fid": 392, - "name": "기준가대비고가등락율", - "offset": 20, - "start": 480 - }, - { - "fid": 393, - "name": "기준가대비저가등락율", - "offset": 20, - "start": 500 - }, - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 520 - }, - { - "fid": 201, - "name": "예상체결가전일종가대비등락율", - "offset": 20, - "start": 540 - }, - { - "fid": 238, - "name": "예상체결가전일종가대비기호", - "offset": 20, - "start": 560 - }, - { - "fid": 200, - "name": "예상체결가전일종가대비", - "offset": 20, - "start": 580 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 600 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 620 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 640 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 660 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 180 - }, - { - "fid": 10, - "name": "풋_현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 11, - "name": "풋_전일대비", - "offset": 20, - "start": 20 - }, - { - "fid": 12, - "name": "풋_등락율", - "offset": 20, - "start": 40 - }, - { - "fid": 25, - "name": "풋_대비기호", - "offset": 20, - "start": 60 - }, - { - "fid": 188, - "name": "풋_시간가치", - "offset": 20, - "start": 80 - }, - { - "fid": 187, - "name": "풋_내재가치", - "offset": 20, - "start": 100 - }, - { - "fid": 189, - "name": "풋_내재변동성", - "offset": 20, - "start": 120 - }, - { - "fid": 182, - "name": "풋_이론가", - "offset": 20, - "start": 140 - }, - { - "fid": 186, - "name": "풋_괴리율", - "offset": 20, - "start": 160 - }, - { - "fid": 181, - "name": "풋_미결제약정전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 195, - "name": "풋_미결제약정", - "offset": 20, - "start": 200 - }, - { - "fid": 14, - "name": "풋_누적거래대금", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "풋_누적거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 125, - "name": "풋_매수호가총잔량", - "offset": 20, - "start": 260 - }, - { - "fid": 121, - "name": "풋_매도호가총잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 71, - "name": "풋_매수호가수량", - "offset": 20, - "start": 300 - }, - { - "fid": 51, - "name": "풋_매수호가", - "offset": 20, - "start": 320 - }, - { - "fid": 61, - "name": "풋_매도호가수량", - "offset": 20, - "start": 340 - }, - { - "fid": 41, - "name": "풋_매도호가", - "offset": 20, - "start": 360 - }, - { - "fid": 307, - "name": "풋_기준가", - "offset": 20, - "start": 380 - }, - { - "fid": 16, - "name": "풋_시가", - "offset": 20, - "start": 400 - }, - { - "fid": 17, - "name": "풋_고가", - "offset": 20, - "start": 420 - }, - { - "fid": 18, - "name": "풋_저가", - "offset": 20, - "start": 440 - }, - { - "fid": 391, - "name": "풋_기준가대비시가등락율", - "offset": 20, - "start": 460 - }, - { - "fid": 392, - "name": "풋_기준가대비고가등락율", - "offset": 20, - "start": 480 - }, - { - "fid": 393, - "name": "풋_기준가대비저가등락율", - "offset": 20, - "start": 500 - }, - { - "fid": 325, - "name": "풋_지수환산", - "offset": 20, - "start": 520 - }, - { - "fid": 201, - "name": "풋_예상체결가전일종가대비등락율", - "offset": 20, - "start": 540 - }, - { - "fid": 238, - "name": "풋_예상체결가전일종가대비기호", - "offset": 20, - "start": 560 - }, - { - "fid": 200, - "name": "풋_예상체결가전일종가대비", - "offset": 20, - "start": 580 - }, - { - "fid": 23, - "name": "풋_예상체결가", - "offset": 20, - "start": 600 - }, - { - "fid": 9001, - "name": "풋_종목코드", - "offset": 20, - "start": 620 - }, - { - "fid": 326, - "name": "풋_ATM구분", - "offset": 20, - "start": 640 - }, - { - "fid": 324, - "name": "풋_행사가", - "offset": 20, - "start": 660 - } - ], - "multi_outputs_name": "복수종목결제월별시세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50020", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50021": { - "gfid": "2102", - "inputs": [ - { - "fid": 9100, - "name": "만기년월", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "콜종목결제월별시세요청", - "multi_outputs": [ - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 0 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 40 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 80 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 100 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 120 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 140 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 160 - }, - { - "fid": 391, - "name": "기준가대비시가등락율", - "offset": 20, - "start": 180 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 200 - }, - { - "fid": 392, - "name": "기준가대비고가등락율", - "offset": 20, - "start": 220 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 240 - }, - { - "fid": 393, - "name": "기준가대비저가등락율", - "offset": 20, - "start": 260 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 280 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 300 - }, - { - "fid": 61, - "name": "매도호가수량", - "offset": 20, - "start": 320 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 340 - }, - { - "fid": 71, - "name": "매수호가수량", - "offset": 20, - "start": 360 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 380 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 400 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 420 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 440 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 460 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 480 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 500 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 520 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 540 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 560 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 580 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 600 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 620 - }, - { - "fid": 193, - "name": "세타", - "offset": 20, - "start": 640 - }, - { - "fid": 192, - "name": "베가", - "offset": 20, - "start": 660 - }, - { - "fid": 194, - "name": "로", - "offset": 20, - "start": 680 - } - ], - "multi_outputs_name": "콜종목결제월별시세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50021", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50022": { - "gfid": "2103", - "inputs": [ - { - "fid": 9100, - "name": "만기년월", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "풋종목결제월별시세요청", - "multi_outputs": [ - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 0 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 40 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 60 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 80 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 100 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 120 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 140 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 160 - }, - { - "fid": 391, - "name": "기준가대비시가등락율", - "offset": 20, - "start": 180 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 200 - }, - { - "fid": 392, - "name": "기준가대비고가등락율", - "offset": 20, - "start": 220 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 240 - }, - { - "fid": 393, - "name": "기준가대비저가등락율", - "offset": 20, - "start": 260 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 280 - }, - { - "fid": 41, - "name": "매도호가", - "offset": 20, - "start": 300 - }, - { - "fid": 61, - "name": "매도호가수량", - "offset": 20, - "start": 320 - }, - { - "fid": 51, - "name": "매수호가", - "offset": 20, - "start": 340 - }, - { - "fid": 71, - "name": "매수호가수량", - "offset": 20, - "start": 360 - }, - { - "fid": 121, - "name": "매도호가총잔량", - "offset": 20, - "start": 380 - }, - { - "fid": 125, - "name": "매수호가총잔량", - "offset": 20, - "start": 400 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 420 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 440 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 460 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 480 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 500 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 520 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 540 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 560 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 580 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 600 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 620 - }, - { - "fid": 193, - "name": "세타", - "offset": 20, - "start": 640 - }, - { - "fid": 192, - "name": "베가", - "offset": 20, - "start": 660 - }, - { - "fid": 194, - "name": "로", - "offset": 20, - "start": 680 - } - ], - "multi_outputs_name": "풋종목결제월별시세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50022", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50023": { - "gfid": "1501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "민감도지표추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 10, - "name": "현재가n", - "offset": 20, - "start": 40 - }, - { - "fid": 182, - "name": "이론가n", - "offset": 20, - "start": 60 - }, - { - "fid": 189, - "name": "내재변동성n", - "offset": 20, - "start": 80 - }, - { - "fid": 190, - "name": "델타n", - "offset": 20, - "start": 100 - }, - { - "fid": 191, - "name": "감마n", - "offset": 20, - "start": 120 - }, - { - "fid": 193, - "name": "세타n", - "offset": 20, - "start": 140 - }, - { - "fid": 192, - "name": "베가n", - "offset": 20, - "start": 160 - }, - { - "fid": 194, - "name": "로n", - "offset": 20, - "start": 180 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 200 - }, - { - "fid": 17, - "name": "고가n", - "offset": 20, - "start": 220 - }, - { - "fid": 18, - "name": "저가n", - "offset": 20, - "start": 240 - }, - { - "fid": 25, - "name": "대비기호n", - "offset": 20, - "start": 260 - }, - { - "fid": 11, - "name": "전일대비n", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "등락율n", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "누적거래량n", - "offset": 20, - "start": 320 - }, - { - "fid": 195, - "name": "미결제약정n", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "민감도지표추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 0 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 20 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 40 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 60 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 80 - }, - { - "fid": 192, - "name": "베가", - "offset": 20, - "start": 100 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 120 - }, - { - "fid": 194, - "name": "로", - "offset": 20, - "start": 140 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 160 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 180 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 280 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 300 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 320 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 340 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 360 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 380 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 400 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 420 - }, - { - "fid": 301, - "name": "종목표준코드", - "offset": 20, - "start": 440 - }, - { - "fid": 187, - "name": "내재가치", - "offset": 20, - "start": 460 - }, - { - "fid": 188, - "name": "시간가치", - "offset": 20, - "start": 480 - } - ], - "single_outputs_name": "민감도지표추이단일", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50023", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50024": { - "gfid": "3076", - "inputs": [ - { - "fid": 9101, - "name": "역사적변동성1", - "offset": 20, - "start": 0 - }, - { - "fid": 9102, - "name": "역사적변동성2", - "offset": 20, - "start": 20 - }, - { - "fid": 9103, - "name": "역사적변동성3", - "offset": 20, - "start": 40 - }, - { - "fid": 9012, - "name": "기간", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "일별변동성분석그래프요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 240, - "name": "대표내재변동성", - "offset": 20, - "start": 20 - }, - { - "fid": 241, - "name": "콜내재변동성", - "offset": 20, - "start": 40 - }, - { - "fid": 242, - "name": "풋내재변동성", - "offset": 20, - "start": 60 - }, - { - "fid": 243, - "name": "선물대표내재변동성", - "offset": 20, - "start": 80 - }, - { - "fid": 244, - "name": "선물콜내재변동성", - "offset": 20, - "start": 100 - }, - { - "fid": 245, - "name": "선물풋내재변동성", - "offset": 20, - "start": 120 - }, - { - "fid": 1201, - "name": "역사적변동성1", - "offset": 20, - "start": 140 - }, - { - "fid": 1202, - "name": "역사적변동성2", - "offset": 20, - "start": 160 - }, - { - "fid": 1203, - "name": "역사적변동성3", - "offset": 20, - "start": 180 - }, - { - "fid": 1204, - "name": "선물역사적변동성1", - "offset": 20, - "start": 200 - }, - { - "fid": 1205, - "name": "선물역사적변동성2", - "offset": 20, - "start": 220 - }, - { - "fid": 1206, - "name": "선물역사적변동성3", - "offset": 20, - "start": 240 - }, - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 260 - } - ], - "multi_outputs_name": "일별변동성분석그래프", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50024", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50025": { - "gfid": "3075", - "inputs": [ - { - "fid": 9101, - "name": "역사적변동성1", - "offset": 20, - "start": 0 - }, - { - "fid": 9102, - "name": "역사적변동성2", - "offset": 20, - "start": 20 - }, - { - "fid": 9103, - "name": "역사적변동성3", - "offset": 20, - "start": 40 - }, - { - "fid": 9012, - "name": "기간", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "시간별변동성분석그래프요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 240, - "name": "대표내재변동성", - "offset": 20, - "start": 20 - }, - { - "fid": 241, - "name": "콜내재변동성", - "offset": 20, - "start": 40 - }, - { - "fid": 242, - "name": "풋내재변동성", - "offset": 20, - "start": 60 - }, - { - "fid": 243, - "name": "선물대표내재변동성", - "offset": 20, - "start": 80 - }, - { - "fid": 244, - "name": "선물콜내재변동성", - "offset": 20, - "start": 100 - }, - { - "fid": 245, - "name": "선물풋내재변동성", - "offset": 20, - "start": 120 - }, - { - "fid": 1201, - "name": "역사적변동성1", - "offset": 20, - "start": 140 - }, - { - "fid": 1202, - "name": "역사적변동성2", - "offset": 20, - "start": 160 - }, - { - "fid": 1203, - "name": "역사적변동성3", - "offset": 20, - "start": 180 - }, - { - "fid": 1204, - "name": "선물역사적변동성1", - "offset": 20, - "start": 200 - }, - { - "fid": 1205, - "name": "선물역사적변동성2", - "offset": 20, - "start": 220 - }, - { - "fid": 1206, - "name": "선물역사적변동성3", - "offset": 20, - "start": 240 - } - ], - "multi_outputs_name": "시간별변동성분석그래프", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50025", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50026": { - "gfid": "8501", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9037, - "name": "조회구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9204, - "name": "매매구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9206, - "name": "체결구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 80 - }, - { - "fid": 9203, - "name": "주문번호", - "offset": 20, - "start": 100 - } - ], - "inputs_name": "선옵주문체결요청", - "multi_outputs": [ - { - "fid": 9203, - "name": "주문번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 40 - }, - { - "fid": 905, - "name": "주문구분", - "offset": 20, - "start": 240 - }, - { - "fid": 901, - "name": "주문가격", - "offset": 20, - "start": 260 - }, - { - "fid": 900, - "name": "주문수량", - "offset": 20, - "start": 280 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 300 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 320 - }, - { - "fid": 902, - "name": "미체결수량", - "offset": 20, - "start": 340 - }, - { - "fid": 913, - "name": "주문상태", - "offset": 20, - "start": 360 - }, - { - "fid": 904, - "name": "원주문번호", - "offset": 20, - "start": 380 - }, - { - "fid": 906, - "name": "매매구분", - "offset": 20, - "start": 400 - }, - { - "fid": 908, - "name": "주문체결시간", - "offset": 20, - "start": 420 - } - ], - "multi_outputs_name": "선옵주문체결", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50026", - "tr_name": "FRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50027": { - "gfid": "8511", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵잔고요청", - "multi_outputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 917, - "name": "신용구분", - "offset": 20, - "start": 40 - }, - { - "fid": 916, - "name": "대출일", - "offset": 20, - "start": 60 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 80 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 320 - }, - { - "fid": 930, - "name": "보유수량", - "offset": 20, - "start": 340 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 360 - }, - { - "fid": 932, - "name": "총매입가", - "offset": 20, - "start": 380 - }, - { - "fid": 933, - "name": "주문가능수량", - "offset": 20, - "start": 400 - }, - { - "fid": 934, - "name": "당일매도수량", - "offset": 20, - "start": 420 - }, - { - "fid": 935, - "name": "당일매도금액", - "offset": 20, - "start": 440 - }, - { - "fid": 936, - "name": "당일매수수량", - "offset": 20, - "start": 460 - }, - { - "fid": 937, - "name": "당일매수금액", - "offset": 20, - "start": 480 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 500 - }, - { - "fid": 939, - "name": "당일매매세금", - "offset": 20, - "start": 520 - }, - { - "fid": 940, - "name": "당일HTS매도수수료", - "offset": 20, - "start": 540 - }, - { - "fid": 941, - "name": "당일HTS매수수수료", - "offset": 20, - "start": 560 - }, - { - "fid": 942, - "name": "D+2매수정산금", - "offset": 20, - "start": 580 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 600 - }, - { - "fid": 945, - "name": "당일순매수량", - "offset": 20, - "start": 620 - }, - { - "fid": 946, - "name": "매매구분", - "offset": 20, - "start": 640 - }, - { - "fid": 950, - "name": "당일총매도손익", - "offset": 20, - "start": 660 - }, - { - "fid": 951, - "name": "예수금", - "offset": 20, - "start": 680 - }, - { - "fid": 27, - "name": "최우선매도호가", - "offset": 20, - "start": 700 - }, - { - "fid": 28, - "name": "최우선매수호가", - "offset": 20, - "start": 720 - }, - { - "fid": 8002, - "name": "결제잔고", - "offset": 20, - "start": 740 - }, - { - "fid": 8003, - "name": "결제금액", - "offset": 20, - "start": 760 - }, - { - "fid": 8004, - "name": "전일매도수량", - "offset": 20, - "start": 780 - }, - { - "fid": 8005, - "name": "전일매수수량", - "offset": 20, - "start": 800 - }, - { - "fid": 8006, - "name": "전일매도금액", - "offset": 20, - "start": 820 - }, - { - "fid": 8007, - "name": "전일매수금액", - "offset": 20, - "start": 840 - }, - { - "fid": 8008, - "name": "전일순매수량", - "offset": 20, - "start": 860 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 880 - }, - { - "fid": 957, - "name": "신용금액", - "offset": 20, - "start": 900 - }, - { - "fid": 958, - "name": "신용이자", - "offset": 20, - "start": 920 - }, - { - "fid": 918, - "name": "만기일", - "offset": 20, - "start": 940 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 960 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 980 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 1000 - }, - { - "fid": 959, - "name": "담보대출수량", - "offset": 20, - "start": 1020 - }, - { - "fid": 397, - "name": "연누적거래대금", - "offset": 20, - "start": 1040 - } - ], - "multi_outputs_name": "선옵잔고", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50027", - "tr_name": "FRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50028": { - "gfid": "3011", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물틱차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "선물틱차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 3501, - "name": "마지막틱갯수", - "offset": 20, - "start": 220 - } - ], - "single_outputs_name": "선물틱차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50028", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50029": { - "gfid": "3012", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물옵션분차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 120 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "선물옵션분차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50029", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50030": { - "gfid": "3013", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물옵션일차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 3501, - "name": "수정주가이벤트", - "offset": 20, - "start": 120 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "선물옵션일차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50030", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50031": { - "gfid": "8506", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵잔고손익요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 8041, - "name": "잔고구분", - "offset": 20, - "start": 20 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 40 - }, - { - "fid": 8018, - "name": "손익", - "offset": 20, - "start": 60 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 80 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 100 - }, - { - "fid": 930, - "name": "보유수량", - "offset": 20, - "start": 120 - }, - { - "fid": 933, - "name": "주문가능수량", - "offset": 20, - "start": 140 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 160 - }, - { - "fid": 932, - "name": "총매입가", - "offset": 20, - "start": 180 - }, - { - "fid": 8040, - "name": "평가금액", - "offset": 20, - "start": 200 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 220 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 240 - } - ], - "multi_outputs_name": "선옵잔고손익", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50031", - "tr_name": "FRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50032": { - "gfid": "8505", - "inputs": [ - { - "fid": 9201, - "name": "계좌번호", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵당일실현손익요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 20 - }, - { - "fid": 8042, - "name": "체결구분", - "offset": 20, - "start": 220 - }, - { - "fid": 911, - "name": "체결량", - "offset": 20, - "start": 240 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 260 - }, - { - "fid": 910, - "name": "체결가", - "offset": 20, - "start": 280 - }, - { - "fid": 944, - "name": "당일매도손익", - "offset": 20, - "start": 300 - }, - { - "fid": 8019, - "name": "손익율", - "offset": 20, - "start": 320 - }, - { - "fid": 938, - "name": "당일매매수수료", - "offset": 20, - "start": 340 - } - ], - "multi_outputs_name": "선옵당일실현손익", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "400", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50032", - "tr_name": "FRJANGO", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50033": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9006, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵잔존일조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 240, - "name": "대표내재변동성", - "offset": 20, - "start": 0 - }, - { - "fid": 241, - "name": "콜내재변동성", - "offset": 20, - "start": 20 - }, - { - "fid": 242, - "name": "풋내재변동성", - "offset": 20, - "start": 40 - }, - { - "fid": 402, - "name": "역사적변동성", - "offset": 20, - "start": 60 - }, - { - "fid": 323, - "name": "잔존일수", - "offset": 20, - "start": 80 - }, - { - "fid": 403, - "name": "영업일기준잔존일", - "offset": 20, - "start": 100 - }, - { - "fid": 404, - "name": "차근달력기준잔존일", - "offset": 20, - "start": 120 - }, - { - "fid": 405, - "name": "차근영업일기준잔존일", - "offset": 20, - "start": 140 - }, - { - "fid": 406, - "name": "차차근달력기준잔존일", - "offset": 20, - "start": 160 - }, - { - "fid": 407, - "name": "차차근영업일기준잔존일", - "offset": 20, - "start": 180 - }, - { - "fid": 408, - "name": "차차차근달력기준잔존일", - "offset": 20, - "start": 200 - }, - { - "fid": 409, - "name": "차차차근영업일기준잔존일", - "offset": 20, - "start": 220 - }, - { - "fid": 243, - "name": "선물대표내재변동성", - "offset": 20, - "start": 240 - }, - { - "fid": 244, - "name": "선물콜내재변동성", - "offset": 20, - "start": 260 - }, - { - "fid": 245, - "name": "선물풋내재변동성", - "offset": 20, - "start": 280 - } - ], - "single_outputs_name": "선옵잔존일조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50033", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50034": { - "gfid": "3016", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9012, - "name": "기간", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선옵전일가격요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - } - ], - "multi_outputs_name": "선옵전일가격", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50034", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50035": { - "gfid": "2404", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9305, - "name": "기간", - "offset": 20, - "start": 40 - }, - { - "fid": 9303, - "name": "차트구분", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "지수변동성차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 80 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 100 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 120 - }, - { - "fid": 13, - "name": "누적거래", - "offset": 20, - "start": 140 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "지수변동성차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50035", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50036": { - "gfid": "2447", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9305, - "name": "기간", - "offset": 20, - "start": 40 - }, - { - "fid": 9303, - "name": "차트구분", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "주요지수변동성차트요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 20 - }, - { - "fid": 1204, - "name": "선물역사적변동성", - "offset": 20, - "start": 40 - } - ], - "multi_outputs_name": "주요지수변동성차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "800", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50036", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50037": { - "gfid": "1502", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "코스피200지수요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 20 - } - ], - "multi_outputs_name": "코스피200지수", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50037", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50038": { - "gfid": "2109", - "inputs": [ - { - "fid": 9048, - "name": "일자구분", - "offset": 20, - "start": 0 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9073, - "name": "투자자구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9036, - "name": "수량금액구분", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "투자자별만기손익차트요청", - "multi_outputs": [ - { - "fid": 13000, - "name": "평가손익", - "offset": 20, - "start": 0 - }, - { - "fid": 931, - "name": "매입단가", - "offset": 20, - "start": 20 - }, - { - "fid": 210, - "name": "투자자별순매수수량", - "offset": 20, - "start": 40 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 60 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 80 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 100 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 140 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 160 - }, - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 180 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 200 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 220 - }, - { - "fid": 9001, - "name": "풋_종목코드", - "offset": 20, - "start": 220 - }, - { - "fid": 10, - "name": "풋_현재가", - "offset": 20, - "start": 240 - }, - { - "fid": 11, - "name": "풋_전일대비", - "offset": 20, - "start": 260 - }, - { - "fid": 25, - "name": "풋_대비기호", - "offset": 20, - "start": 280 - }, - { - "fid": 195, - "name": "풋_미결제약정", - "offset": 20, - "start": 300 - }, - { - "fid": 210, - "name": "풋_투자자별순매수수량", - "offset": 20, - "start": 320 - }, - { - "fid": 931, - "name": "풋_매입단가", - "offset": 20, - "start": 340 - }, - { - "fid": 13000, - "name": "풋_평가손익", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "투자자별만기손익차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "0", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50038", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50039": { - "gfid": "STOCKG", - "inputs": [ - { - "fid": 9048, - "name": "일자구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9036, - "name": "수량금액구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9040, - "name": "단위구분", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "투자자별포지션종합요청", - "multi_outputs": [ - { - "fid": 1111, - "name": "기간중주가등락", - "offset": 20, - "start": 0 - }, - { - "fid": 1107, - "name": "기타법인", - "offset": 20, - "start": 20 - }, - { - "fid": 1106, - "name": "연기금등", - "offset": 20, - "start": 40 - }, - { - "fid": 1105, - "name": "기타금융", - "offset": 20, - "start": 60 - }, - { - "fid": 1104, - "name": "은행", - "offset": 20, - "start": 80 - }, - { - "fid": 1103, - "name": "투신", - "offset": 20, - "start": 100 - }, - { - "fid": 1102, - "name": "보험", - "offset": 20, - "start": 120 - }, - { - "fid": 1101, - "name": "금융투자", - "offset": 20, - "start": 140 - }, - { - "fid": 1109, - "name": "외국인", - "offset": 20, - "start": 160 - }, - { - "fid": 1108, - "name": "개인", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 220 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 240 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 260 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 300 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 320 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 340 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 360 - }, - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 380 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 140 - }, - { - "fid": 9001, - "name": "풋_종목코드", - "offset": 20, - "start": 400 - }, - { - "fid": 10, - "name": "풋_현재가", - "offset": 20, - "start": 420 - }, - { - "fid": 12, - "name": "풋_등락율", - "offset": 20, - "start": 440 - }, - { - "fid": 25, - "name": "풋_대비기호", - "offset": 20, - "start": 460 - }, - { - "fid": 11, - "name": "풋_전일대비", - "offset": 20, - "start": 480 - }, - { - "fid": 195, - "name": "풋_미결제약정", - "offset": 20, - "start": 500 - }, - { - "fid": 181, - "name": "풋_미결제약정전일대비", - "offset": 20, - "start": 520 - }, - { - "fid": 13, - "name": "풋_누적거래량", - "offset": 20, - "start": 540 - }, - { - "fid": 326, - "name": "풋_ATM구분", - "offset": 20, - "start": 560 - }, - { - "fid": 1108, - "name": "풋_개인", - "offset": 20, - "start": 580 - }, - { - "fid": 1109, - "name": "풋_외국인", - "offset": 20, - "start": 600 - }, - { - "fid": 1101, - "name": "풋_금융투자", - "offset": 20, - "start": 620 - }, - { - "fid": 1102, - "name": "풋_보험", - "offset": 20, - "start": 640 - }, - { - "fid": 1103, - "name": "풋_투신", - "offset": 20, - "start": 660 - }, - { - "fid": 1104, - "name": "풋_은행", - "offset": 20, - "start": 680 - }, - { - "fid": 1105, - "name": "풋_기타금융", - "offset": 20, - "start": 700 - }, - { - "fid": 1106, - "name": "풋_연기금등", - "offset": 20, - "start": 720 - }, - { - "fid": 1107, - "name": "풋_기타법인", - "offset": 20, - "start": 740 - }, - { - "fid": 1111, - "name": "풋_기간중주가등락", - "offset": 20, - "start": 760 - } - ], - "multi_outputs_name": "투자자별포지션종합", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50039", - "tr_name": "PIBOFIDF", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50040": { - "gfid": "1505", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선옵시고저가요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 40 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 60 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 80 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 100 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 120 - }, - { - "fid": 246, - "name": "시초미결제약정수량", - "offset": 20, - "start": 140 - }, - { - "fid": 247, - "name": "최고미결제약정수량", - "offset": 20, - "start": 160 - }, - { - "fid": 248, - "name": "최저미결제약정수량", - "offset": 20, - "start": 180 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 200 - }, - { - "fid": 269, - "name": "전일미결제약정", - "offset": 20, - "start": 220 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 240 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 260 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 280 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 300 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 320 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 340 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 360 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 380 - } - ], - "multi_outputs_name": "선옵시고저가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50040", - "tr_name": "FOCODTR", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50043": { - "gfid": "2214", - "inputs": [ - { - "fid": 9091, - "name": "거래대금구분", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "주식선물거래량상위종목요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 301, - "name": "종목표준코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 240 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 260 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 320 - } - ], - "multi_outputs_name": "주식선물거래량상위종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50043", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50044": { - "gfid": "2215", - "inputs": [ - { - "fid": 9100, - "name": "근월물구분", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "주식선물시세표요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 301, - "name": "종목표준코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 200, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 240 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 260 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 280 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 300 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 320 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 340 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 360 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 380 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 400 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 420 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 440 - }, - { - "fid": 28, - "name": "최우선매수호가", - "offset": 20, - "start": 460 - }, - { - "fid": 27, - "name": "최우선매도호가", - "offset": 20, - "start": 480 - }, - { - "fid": 197, - "name": "코스피200", - "offset": 20, - "start": 500 - } - ], - "multi_outputs_name": "주식선물시세표", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "200", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1101, - "name": "거래량합계", - "offset": 20, - "start": 0 - }, - { - "fid": 1102, - "name": "거래대금합계", - "offset": 20, - "start": 20 - } - ], - "single_outputs_name": "거래량합계", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50044", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50062": { - "gfid": "3012", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물미결제약정분차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 40 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "선물미결제약정분차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가s", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호s", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비s", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율s", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가s", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가s", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량s", - "offset": 20, - "start": 120 - }, - { - "fid": 195, - "name": "미결제약정s", - "offset": 20, - "start": 140 - }, - { - "fid": 302, - "name": "종목명s", - "offset": 200, - "start": 160 - } - ], - "single_outputs_name": "선물현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50062", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50063": { - "gfid": "3023", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "옵션미결제약정일차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 22, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 40 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "옵션미결제약정일차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가s", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호s", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비s", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율s", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가s", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가s", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량s", - "offset": 20, - "start": 120 - }, - { - "fid": 195, - "name": "미결제약정s", - "offset": 20, - "start": 140 - }, - { - "fid": 302, - "name": "종목명s", - "offset": 200, - "start": 160 - } - ], - "single_outputs_name": "옵션현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50063", - "tr_name": "OCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50064": { - "gfid": "3022", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "옵션미결제약정분차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 20 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 40 - }, - { - "fid": 196, - "name": "미결제증감", - "offset": 20, - "start": 60 - } - ], - "multi_outputs_name": "옵션미결제약정분차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 10, - "name": "현재가s", - "offset": 20, - "start": 0 - }, - { - "fid": 25, - "name": "대비기호s", - "offset": 20, - "start": 20 - }, - { - "fid": 11, - "name": "전일대비s", - "offset": 20, - "start": 40 - }, - { - "fid": 12, - "name": "등락율s", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가s", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가s", - "offset": 20, - "start": 100 - }, - { - "fid": 13, - "name": "누적거래량s", - "offset": 20, - "start": 120 - }, - { - "fid": 195, - "name": "미결제약정s", - "offset": 20, - "start": 140 - }, - { - "fid": 302, - "name": "종목명s", - "offset": 200, - "start": 160 - } - ], - "single_outputs_name": "옵션현재가정보", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50064", - "tr_name": "OCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50065": { - "gfid": "2103", - "inputs": [ - { - "fid": 9100, - "name": "만기년월", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "풋옵션행사가요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 326, - "name": "ATM구분", - "offset": 20, - "start": 20 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 40 - } - ], - "multi_outputs_name": "풋옵션행사가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50065", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50066": { - "gfid": "3021", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "옵션틱차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "옵션틱차트조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 3501, - "name": "마지막틱갯수", - "offset": 20, - "start": 220 - } - ], - "single_outputs_name": "옵션틱차트", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt50066", - "tr_name": "OCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50067": { - "gfid": "3022", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9007, - "name": "시간단위", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "옵션분차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 15, - "name": "거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "옵션분차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50067", - "tr_name": "OCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50068": { - "gfid": "3023", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "옵션일차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "옵션일차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "900", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50068", - "tr_name": "OCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50071": { - "gfid": "3014", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물주차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "선물주차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50071", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50072": { - "gfid": "3015", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물월차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "선물월차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50072", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt50073": { - "gfid": "3017", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "선물년차트요청", - "multi_outputs": [ - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 0 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 20 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 40 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 60 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 80 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 100 - }, - { - "fid": 346, - "name": "전일종가", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "선물년차트", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "600", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt50073", - "tr_name": "FCHART", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90001": { - "gfid": "2361", - "inputs": [ - { - "fid": 9039, - "name": "검색구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 9012, - "name": "날짜구분", - "offset": 20, - "start": 40 - }, - { - "fid": 352, - "name": "테마명", - "offset": 200, - "start": 60 - }, - { - "fid": 9013, - "name": "등락수익구분", - "offset": 20, - "start": 260 - } - ], - "inputs_name": "테마그룹별요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 352, - "name": "테마명", - "offset": 200, - "start": 20 - }, - { - "fid": 1051, - "name": "종목수", - "offset": 20, - "start": 220 - }, - { - "fid": 25, - "name": "등락기호", - "offset": 20, - "start": 240 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 260 - }, - { - "fid": 1052, - "name": "상승종목수", - "offset": 20, - "start": 280 - }, - { - "fid": 1054, - "name": "하락종목수", - "offset": 20, - "start": 300 - }, - { - "fid": 353, - "name": "기간수익률", - "offset": 20, - "start": 320 - }, - { - "fid": 1079, - "name": "주요종목", - "offset": 1000, - "start": 340 - } - ], - "multi_outputs_name": "테마그룹별", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90001", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90002": { - "gfid": "2362", - "inputs": [ - { - "fid": 9012, - "name": "날짜구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "테마구성종목요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "등락기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 180 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 200 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 220 - }, - { - "fid": 61, - "name": "매도잔량", - "offset": 20, - "start": 240 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 260 - }, - { - "fid": 71, - "name": "매수잔량", - "offset": 20, - "start": 280 - }, - { - "fid": 353, - "name": "기간수익률n", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "테마구성종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 12, - "name": "등락률", - "offset": 20, - "start": 0 - }, - { - "fid": 353, - "name": "기간수익률", - "offset": 20, - "start": 20 - } - ], - "single_outputs_name": "테마구성종목단일", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt90002", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90003": { - "gfid": "2351", - "inputs": [ - { - "fid": 9035, - "name": "매매상위구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "시장구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "프로그램순매수상위50요청", - "multi_outputs": [ - { - "fid": 401, - "name": "순위", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 20 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 40 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 140 - }, - { - "fid": 25, - "name": "등락기호", - "offset": 20, - "start": 160 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "누적거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 204, - "name": "프로그램매도금액", - "offset": 20, - "start": 240 - }, - { - "fid": 208, - "name": "프로그램매수금액", - "offset": 20, - "start": 260 - }, - { - "fid": 212, - "name": "프로그램순매수금액", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "프로그램순매수상위50", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "15", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90003", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90004": { - "gfid": "2352", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9001, - "name": "시장구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "종목별프로그램매매현황요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 25, - "name": "등락기호", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 206, - "name": "매수체결수량", - "offset": 20, - "start": 180 - }, - { - "fid": 208, - "name": "매수체결금액", - "offset": 20, - "start": 200 - }, - { - "fid": 202, - "name": "매도체결수량", - "offset": 20, - "start": 220 - }, - { - "fid": 204, - "name": "매도체결금액", - "offset": 20, - "start": 240 - }, - { - "fid": 212, - "name": "순매수대금", - "offset": 20, - "start": 260 - }, - { - "fid": 1077, - "name": "전체거래비율", - "offset": 20, - "start": 280 - } - ], - "multi_outputs_name": "종목별프로그램매매현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 1101, - "name": "합계1", - "offset": 20, - "start": 0 - }, - { - "fid": 1102, - "name": "합계2", - "offset": 20, - "start": 20 - }, - { - "fid": 1103, - "name": "합계3", - "offset": 20, - "start": 40 - }, - { - "fid": 1104, - "name": "합계4", - "offset": 20, - "start": 60 - }, - { - "fid": 1105, - "name": "합계5", - "offset": 20, - "start": 80 - }, - { - "fid": 1106, - "name": "합계6", - "offset": 20, - "start": 100 - } - ], - "single_outputs_name": "종목별프로그램매매합계", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt90004", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90005": { - "gfid": "2354", - "inputs": [ - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 9038, - "name": "시간구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 40 - }, - { - "fid": 9001, - "name": "시장구분", - "offset": 20, - "start": 60 - }, - { - "fid": 9007, - "name": "분틱구분", - "offset": 20, - "start": 80 - } - ], - "inputs_name": "프로그램매매추이요청", - "multi_outputs": [ - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 0 - }, - { - "fid": 505, - "name": "차익거래매도", - "offset": 20, - "start": 20 - }, - { - "fid": 514, - "name": "차익거래매수", - "offset": 20, - "start": 40 - }, - { - "fid": 522, - "name": "차익거래순매수", - "offset": 20, - "start": 60 - }, - { - "fid": 529, - "name": "비차익거래매도", - "offset": 20, - "start": 80 - }, - { - "fid": 538, - "name": "비차익거래매수", - "offset": 20, - "start": 100 - }, - { - "fid": 546, - "name": "비차익거래순매수", - "offset": 20, - "start": 120 - }, - { - "fid": 502, - "name": "차익거래매도수량", - "offset": 20, - "start": 20 - }, - { - "fid": 511, - "name": "차익거래매수수량", - "offset": 20, - "start": 40 - }, - { - "fid": 523, - "name": "차익거래순매수수량", - "offset": 20, - "start": 60 - }, - { - "fid": 526, - "name": "비차익거래매도수량", - "offset": 20, - "start": 80 - }, - { - "fid": 535, - "name": "비차익거래매수수량", - "offset": 20, - "start": 100 - }, - { - "fid": 547, - "name": "비차익거래순매수수량", - "offset": 20, - "start": 120 - }, - { - "fid": 204, - "name": "전체매도", - "offset": 20, - "start": 140 - }, - { - "fid": 208, - "name": "전체매수", - "offset": 20, - "start": 160 - }, - { - "fid": 212, - "name": "전체순매수", - "offset": 20, - "start": 180 - }, - { - "fid": 197, - "name": "KOSPI200", - "offset": 20, - "start": 200 - }, - { - "fid": 183, - "name": "BASIS", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "프로그램매매추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90005", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90006": { - "gfid": "2355", - "inputs": [ - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "프로그램매매차익잔고추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 511, - "name": "매수차익거래수량", - "offset": 20, - "start": 20 - }, - { - "fid": 514, - "name": "매수차익거래금액", - "offset": 20, - "start": 40 - }, - { - "fid": 553, - "name": "매수차익거래증감액", - "offset": 20, - "start": 60 - }, - { - "fid": 502, - "name": "매도차익거래수량", - "offset": 20, - "start": 80 - }, - { - "fid": 505, - "name": "매도차익거래금액", - "offset": 20, - "start": 100 - }, - { - "fid": 552, - "name": "매도차익거래증감액", - "offset": 20, - "start": 120 - } - ], - "multi_outputs_name": "프로그램매매차익잔고추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90006", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90007": { - "gfid": "2358", - "inputs": [ - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "시장구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "프로그램매매누적추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 197, - "name": "KOSPI200", - "offset": 20, - "start": 20 - }, - { - "fid": 183, - "name": "BASIS", - "offset": 20, - "start": 40 - }, - { - "fid": 522, - "name": "차익거래당일", - "offset": 20, - "start": 60 - }, - { - "fid": 524, - "name": "차익거래누적", - "offset": 20, - "start": 80 - }, - { - "fid": 546, - "name": "비차익거래당일", - "offset": 20, - "start": 100 - }, - { - "fid": 548, - "name": "비차익거래누적", - "offset": 20, - "start": 120 - }, - { - "fid": 764, - "name": "전체당일", - "offset": 20, - "start": 140 - }, - { - "fid": 765, - "name": "전체누적", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "프로그램매매누적추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90007", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90008": { - "gfid": "2360", - "inputs": [ - { - "fid": 9038, - "name": "시간일자구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 40 - }, - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "종목시간별프로그램매매추이요청", - "multi_outputs": [ - { - "fid": 20, - "name": "시간", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 204, - "name": "프로그램매도금액", - "offset": 20, - "start": 120 - }, - { - "fid": 208, - "name": "프로그램매수금액", - "offset": 20, - "start": 140 - }, - { - "fid": 212, - "name": "프로그램순매수금액", - "offset": 20, - "start": 160 - }, - { - "fid": 213, - "name": "프로그램순매수금액증감", - "offset": 20, - "start": 160 - }, - { - "fid": 202, - "name": "프로그램매도수량", - "offset": 20, - "start": 120 - }, - { - "fid": 206, - "name": "프로그램매수수량", - "offset": 20, - "start": 140 - }, - { - "fid": 210, - "name": "프로그램순매수수량", - "offset": 20, - "start": 160 - }, - { - "fid": 211, - "name": "프로그램순매수수량증감", - "offset": 20, - "start": 160 - }, - { - "fid": 1041, - "name": "기준가시간", - "offset": 20, - "start": 180 - }, - { - "fid": 1042, - "name": "대차거래상환주수합", - "offset": 20, - "start": 200 - }, - { - "fid": 1043, - "name": "잔고수주합", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "종목시간별프로그램매매추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90008", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90009": { - "gfid": "2311", - "inputs": [ - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9040, - "name": "조회일자구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "외국인기관매매상위요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "외인순매도종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "외인순매도종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 212, - "name": "외인순매도금액", - "offset": 20, - "start": 120 - }, - { - "fid": 210, - "name": "외인순매도수량", - "offset": 20, - "start": 140 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 140 - }, - { - "fid": 9001, - "name": "외인순매수종목코드", - "offset": 20, - "start": 160 - }, - { - "fid": 302, - "name": "외인순매수종목명", - "offset": 100, - "start": 180 - }, - { - "fid": 212, - "name": "외인순매수금액", - "offset": 20, - "start": 280 - }, - { - "fid": 210, - "name": "외인순매수수량", - "offset": 20, - "start": 300 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 140 - }, - { - "fid": 9001, - "name": "기관순매도종목코드", - "offset": 20, - "start": 160 - }, - { - "fid": 302, - "name": "기관순매도종목명", - "offset": 100, - "start": 180 - }, - { - "fid": 212, - "name": "기관순매도금액", - "offset": 20, - "start": 280 - }, - { - "fid": 210, - "name": "기관순매도수량", - "offset": 20, - "start": 300 - }, - { - "fid": 0, - "name": "대칭구분", - "offset": 20, - "start": 140 - }, - { - "fid": 9001, - "name": "기관순매수종목코드", - "offset": 20, - "start": 160 - }, - { - "fid": 302, - "name": "기관순매수종목명", - "offset": 100, - "start": 180 - }, - { - "fid": 212, - "name": "기관순매수금액", - "offset": 20, - "start": 280 - }, - { - "fid": 210, - "name": "기관순매수수량", - "offset": 20, - "start": 300 - } - ], - "multi_outputs_name": "외국인기관매매상위", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "25", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90009", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90010": { - "gfid": "2357", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "차익잔고현황요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드1", - "offset": 20, - "start": 0 - }, - { - "fid": 503, - "name": "차익매도위탁금액", - "offset": 20, - "start": 20 - }, - { - "fid": 512, - "name": "차익매수위탁금액", - "offset": 20, - "start": 40 - }, - { - "fid": 1121, - "name": "차익매도위탁선물금액", - "offset": 20, - "start": 60 - }, - { - "fid": 1123, - "name": "차익매수위탁선물금액", - "offset": 20, - "start": 80 - }, - { - "fid": 1125, - "name": "차익매도위탁CALL금액", - "offset": 20, - "start": 100 - }, - { - "fid": 1127, - "name": "차익매수위탁CALL금액", - "offset": 20, - "start": 120 - }, - { - "fid": 1129, - "name": "차익매도위탁PUT금액", - "offset": 20, - "start": 140 - }, - { - "fid": 1131, - "name": "차익매수위탁PUT금액", - "offset": 20, - "start": 160 - }, - { - "fid": 504, - "name": "차익매도자기금액", - "offset": 20, - "start": 180 - }, - { - "fid": 513, - "name": "차익매수자기금액", - "offset": 20, - "start": 200 - }, - { - "fid": 1122, - "name": "차익매도자기선물금액", - "offset": 20, - "start": 220 - }, - { - "fid": 1124, - "name": "차익매수자기선물금액", - "offset": 20, - "start": 240 - }, - { - "fid": 1126, - "name": "차익매도자기CALL금액", - "offset": 20, - "start": 260 - }, - { - "fid": 1128, - "name": "차익매수자기CALL금액", - "offset": 20, - "start": 280 - }, - { - "fid": 1130, - "name": "차익매도자기PUT금액", - "offset": 20, - "start": 300 - }, - { - "fid": 1132, - "name": "차익매수자기PUT금액", - "offset": 20, - "start": 320 - }, - { - "fid": 505, - "name": "차익매도금액", - "offset": 20, - "start": 340 - }, - { - "fid": 514, - "name": "차익매수금액", - "offset": 20, - "start": 360 - }, - { - "fid": 1179, - "name": "차익매도선물금액", - "offset": 20, - "start": 380 - }, - { - "fid": 1180, - "name": "차익매수선물금액", - "offset": 20, - "start": 400 - }, - { - "fid": 1181, - "name": "차익매도CALL금액", - "offset": 20, - "start": 420 - }, - { - "fid": 1182, - "name": "차익매수CALL금액", - "offset": 20, - "start": 440 - }, - { - "fid": 1183, - "name": "차익매도PUT금액", - "offset": 20, - "start": 460 - }, - { - "fid": 1184, - "name": "차익매수PUT금액", - "offset": 20, - "start": 480 - }, - { - "fid": 9001, - "name": "종목코드2", - "offset": 20, - "start": 500 - }, - { - "fid": 503, - "name": "차익매도위탁금액2", - "offset": 20, - "start": 520 - }, - { - "fid": 512, - "name": "차익매수위탁금액2", - "offset": 20, - "start": 540 - }, - { - "fid": 1121, - "name": "차익매도위탁선물금액2", - "offset": 20, - "start": 560 - }, - { - "fid": 1123, - "name": "차익매수위탁선물금액2", - "offset": 20, - "start": 580 - }, - { - "fid": 1125, - "name": "차익매도위탁CALL금액2", - "offset": 20, - "start": 600 - }, - { - "fid": 1127, - "name": "차익매수위탁CALL금액2", - "offset": 20, - "start": 620 - }, - { - "fid": 1129, - "name": "차익매도위탁PUT금액2", - "offset": 20, - "start": 640 - }, - { - "fid": 1131, - "name": "차익매수위탁PUT금액2", - "offset": 20, - "start": 660 - }, - { - "fid": 504, - "name": "차익매도자기금액2", - "offset": 20, - "start": 680 - }, - { - "fid": 513, - "name": "차익매수자기금액2", - "offset": 20, - "start": 700 - }, - { - "fid": 1122, - "name": "차익매도자기선물금액2", - "offset": 20, - "start": 720 - }, - { - "fid": 1124, - "name": "차익매수자기선물금액2", - "offset": 20, - "start": 740 - }, - { - "fid": 1126, - "name": "차익매도자기CALL금액2", - "offset": 20, - "start": 760 - }, - { - "fid": 1128, - "name": "차익매수자기CALL금액2", - "offset": 20, - "start": 780 - }, - { - "fid": 1130, - "name": "차익매도자기PUT금액2", - "offset": 20, - "start": 800 - }, - { - "fid": 1132, - "name": "차익매수자기PUT금액2", - "offset": 20, - "start": 820 - }, - { - "fid": 505, - "name": "차익매도금액2", - "offset": 20, - "start": 840 - }, - { - "fid": 514, - "name": "차익매수금액2", - "offset": 20, - "start": 860 - }, - { - "fid": 1179, - "name": "차익매도선물금액2", - "offset": 20, - "start": 880 - }, - { - "fid": 1180, - "name": "차익매수선물금액2", - "offset": 20, - "start": 900 - }, - { - "fid": 1181, - "name": "차익매도CALL금액2", - "offset": 20, - "start": 920 - }, - { - "fid": 1182, - "name": "차익매수CALL금액2", - "offset": 20, - "start": 940 - }, - { - "fid": 1183, - "name": "차익매도PUT금액2", - "offset": 20, - "start": 960 - }, - { - "fid": 1184, - "name": "차익매수PUT금액2", - "offset": 20, - "start": 980 - } - ], - "multi_outputs_name": "차익잔고현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "기준일자", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt90010", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90011": { - "gfid": "2357", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "차익잔고현황요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드1", - "offset": 20, - "start": 0 - }, - { - "fid": 503, - "name": "차익매도위탁금액", - "offset": 20, - "start": 20 - }, - { - "fid": 512, - "name": "차익매수위탁금액", - "offset": 20, - "start": 40 - }, - { - "fid": 1121, - "name": "차익매도위탁선물금액", - "offset": 20, - "start": 60 - }, - { - "fid": 1123, - "name": "차익매수위탁선물금액", - "offset": 20, - "start": 80 - }, - { - "fid": 1125, - "name": "차익매도위탁CALL금액", - "offset": 20, - "start": 100 - }, - { - "fid": 1127, - "name": "차익매수위탁CALL금액", - "offset": 20, - "start": 120 - }, - { - "fid": 1129, - "name": "차익매도위탁PUT금액", - "offset": 20, - "start": 140 - }, - { - "fid": 1131, - "name": "차익매수위탁PUT금액", - "offset": 20, - "start": 160 - }, - { - "fid": 504, - "name": "차익매도자기금액", - "offset": 20, - "start": 180 - }, - { - "fid": 513, - "name": "차익매수자기금액", - "offset": 20, - "start": 200 - }, - { - "fid": 1122, - "name": "차익매도자기선물금액", - "offset": 20, - "start": 220 - }, - { - "fid": 1124, - "name": "차익매수자기선물금액", - "offset": 20, - "start": 240 - }, - { - "fid": 1126, - "name": "차익매도자기CALL금액", - "offset": 20, - "start": 260 - }, - { - "fid": 1128, - "name": "차익매수자기CALL금액", - "offset": 20, - "start": 280 - }, - { - "fid": 1130, - "name": "차익매도자기PUT금액", - "offset": 20, - "start": 300 - }, - { - "fid": 1132, - "name": "차익매수자기PUT금액", - "offset": 20, - "start": 320 - }, - { - "fid": 505, - "name": "차익매도금액", - "offset": 20, - "start": 340 - }, - { - "fid": 514, - "name": "차익매수금액", - "offset": 20, - "start": 360 - }, - { - "fid": 1179, - "name": "차익매도선물금액", - "offset": 20, - "start": 380 - }, - { - "fid": 1180, - "name": "차익매수선물금액", - "offset": 20, - "start": 400 - }, - { - "fid": 1181, - "name": "차익매도CALL금액", - "offset": 20, - "start": 420 - }, - { - "fid": 1182, - "name": "차익매수CALL금액", - "offset": 20, - "start": 440 - }, - { - "fid": 1183, - "name": "차익매도PUT금액", - "offset": 20, - "start": 460 - }, - { - "fid": 1184, - "name": "차익매수PUT금액", - "offset": 20, - "start": 480 - }, - { - "fid": 9001, - "name": "종목코드2", - "offset": 20, - "start": 500 - }, - { - "fid": 503, - "name": "차익매도위탁금액2", - "offset": 20, - "start": 520 - }, - { - "fid": 512, - "name": "차익매수위탁금액2", - "offset": 20, - "start": 540 - }, - { - "fid": 1121, - "name": "차익매도위탁선물금액2", - "offset": 20, - "start": 560 - }, - { - "fid": 1123, - "name": "차익매수위탁선물금액2", - "offset": 20, - "start": 580 - }, - { - "fid": 1125, - "name": "차익매도위탁CALL금액2", - "offset": 20, - "start": 600 - }, - { - "fid": 1127, - "name": "차익매수위탁CALL금액2", - "offset": 20, - "start": 620 - }, - { - "fid": 1129, - "name": "차익매도위탁PUT금액2", - "offset": 20, - "start": 640 - }, - { - "fid": 1131, - "name": "차익매수위탁PUT금액2", - "offset": 20, - "start": 660 - }, - { - "fid": 504, - "name": "차익매도자기금액2", - "offset": 20, - "start": 680 - }, - { - "fid": 513, - "name": "차익매수자기금액2", - "offset": 20, - "start": 700 - }, - { - "fid": 1122, - "name": "차익매도자기선물금액2", - "offset": 20, - "start": 720 - }, - { - "fid": 1124, - "name": "차익매수자기선물금액2", - "offset": 20, - "start": 740 - }, - { - "fid": 1126, - "name": "차익매도자기CALL금액2", - "offset": 20, - "start": 760 - }, - { - "fid": 1128, - "name": "차익매수자기CALL금액2", - "offset": 20, - "start": 780 - }, - { - "fid": 1130, - "name": "차익매도자기PUT금액2", - "offset": 20, - "start": 800 - }, - { - "fid": 1132, - "name": "차익매수자기PUT금액2", - "offset": 20, - "start": 820 - }, - { - "fid": 505, - "name": "차익매도금액2", - "offset": 20, - "start": 840 - }, - { - "fid": 514, - "name": "차익매수금액2", - "offset": 20, - "start": 860 - }, - { - "fid": 1179, - "name": "차익매도선물금액2", - "offset": 20, - "start": 880 - }, - { - "fid": 1180, - "name": "차익매수선물금액2", - "offset": 20, - "start": 900 - }, - { - "fid": 1181, - "name": "차익매도CALL금액2", - "offset": 20, - "start": 920 - }, - { - "fid": 1182, - "name": "차익매수CALL금액2", - "offset": 20, - "start": 940 - }, - { - "fid": 1183, - "name": "차익매도PUT금액2", - "offset": 20, - "start": 960 - }, - { - "fid": 1184, - "name": "차익매수PUT금액2", - "offset": 20, - "start": 980 - } - ], - "multi_outputs_name": "차익잔고현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [ - { - "fid": 9004, - "name": "기준일자", - "offset": 20, - "start": 0 - } - ], - "single_outputs_name": "기준일자", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opt90011", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90012": { - "gfid": "2216", - "inputs": [ - { - "fid": 9004, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 20 - } - ], - "inputs_name": "대차거래내역요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 389, - "name": "종목코드", - "offset": 20, - "start": 100 - }, - { - "fid": 312, - "name": "대차거래체결주수", - "offset": 20, - "start": 120 - }, - { - "fid": 470, - "name": "대차거래상환주수", - "offset": 20, - "start": 140 - }, - { - "fid": 471, - "name": "잔고주수", - "offset": 20, - "start": 160 - }, - { - "fid": 472, - "name": "잔고금액", - "offset": 20, - "start": 180 - } - ], - "multi_outputs_name": "대차거래내역", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "50", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90012", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt90013": { - "gfid": "2359", - "inputs": [ - { - "fid": 9038, - "name": "시간일자구분", - "offset": 20, - "start": 0 - }, - { - "fid": 9036, - "name": "금액수량구분", - "offset": 20, - "start": 20 - }, - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 40 - }, - { - "fid": 9004, - "name": "날짜", - "offset": 20, - "start": 60 - } - ], - "inputs_name": "종목일별프로그램매매추이요청", - "multi_outputs": [ - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 0 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 20 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 40 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 60 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 80 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 100 - }, - { - "fid": 204, - "name": "프로그램매도금액", - "offset": 20, - "start": 120 - }, - { - "fid": 208, - "name": "프로그램매수금액", - "offset": 20, - "start": 140 - }, - { - "fid": 212, - "name": "프로그램순매수금액", - "offset": 20, - "start": 160 - }, - { - "fid": 928, - "name": "프로그램순매수금액증감", - "offset": 20, - "start": 160 - }, - { - "fid": 202, - "name": "프로그램매도수량", - "offset": 20, - "start": 120 - }, - { - "fid": 206, - "name": "프로그램매수수량", - "offset": 20, - "start": 140 - }, - { - "fid": 210, - "name": "프로그램순매수수량", - "offset": 20, - "start": 160 - }, - { - "fid": 929, - "name": "프로그램순매수수량증감", - "offset": 20, - "start": 160 - }, - { - "fid": 1041, - "name": "기준가시간", - "offset": 20, - "start": 180 - }, - { - "fid": 1042, - "name": "대차거래상환주수합", - "offset": 20, - "start": 200 - }, - { - "fid": 1043, - "name": "잔고수주합", - "offset": 20, - "start": 220 - } - ], - "multi_outputs_name": "종목일별프로그램매매추이", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "20", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt90013", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opt99999": { - "gfid": "2218", - "inputs": [ - { - "fid": 9004, - "name": "시작일자", - "offset": 20, - "start": 0 - }, - { - "fid": 9005, - "name": "종료일자", - "offset": 20, - "start": 20 - }, - { - "fid": 9008, - "name": "시장구분", - "offset": 20, - "start": 40 - } - ], - "inputs_name": "대차거래상위10종목요청", - "multi_outputs": [ - { - "fid": 1041, - "name": "일자1", - "offset": 20, - "start": 0 - }, - { - "fid": 1042, - "name": "일자2", - "offset": 20, - "start": 20 - }, - { - "fid": 1043, - "name": "일자3", - "offset": 20, - "start": 40 - }, - { - "fid": 1044, - "name": "일자4", - "offset": 20, - "start": 60 - }, - { - "fid": 1045, - "name": "일자5", - "offset": 20, - "start": 80 - }, - { - "fid": 1046, - "name": "일자6", - "offset": 20, - "start": 100 - }, - { - "fid": 1047, - "name": "일자7", - "offset": 20, - "start": 120 - }, - { - "fid": 1048, - "name": "일자8", - "offset": 20, - "start": 140 - } - ], - "multi_outputs_name": "대차거래상위10종목합계", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "opt99999", - "tr_name": "PIHOFNWS", - "tr_name_svr": "", - "tr_type": "1" - }, - "optfofid": { - "gfid": "1505", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "선물전체시세요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 140 - }, - { - "fid": 42, - "name": "매도호가2", - "offset": 20, - "start": 160 - }, - { - "fid": 41, - "name": "매도호가1", - "offset": 20, - "start": 180 - }, - { - "fid": 51, - "name": "매수호가1", - "offset": 20, - "start": 200 - }, - { - "fid": 52, - "name": "매수호가2", - "offset": 20, - "start": 220 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 240 - }, - { - "fid": 26, - "name": "거래량전일대비", - "offset": 20, - "start": 260 - }, - { - "fid": 14, - "name": "누적거래대금", - "offset": 20, - "start": 280 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 300 - }, - { - "fid": 181, - "name": "미결제약정전일대비", - "offset": 20, - "start": 320 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 340 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 360 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 380 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 400 - }, - { - "fid": 186, - "name": "괴리율", - "offset": 20, - "start": 420 - }, - { - "fid": 183, - "name": "시장베이시스", - "offset": 20, - "start": 440 - }, - { - "fid": 184, - "name": "이론베이시스", - "offset": 20, - "start": 460 - }, - { - "fid": 324, - "name": "행사가", - "offset": 20, - "start": 480 - }, - { - "fid": 325, - "name": "지수환산", - "offset": 20, - "start": 500 - }, - { - "fid": 25, - "name": "대비기호", - "offset": 20, - "start": 520 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 540 - }, - { - "fid": 71, - "name": "매수수량", - "offset": 20, - "start": 560 - }, - { - "fid": 127, - "name": "매수호가총건수", - "offset": 20, - "start": 580 - }, - { - "fid": 123, - "name": "매도호가총건수", - "offset": 20, - "start": 600 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 620 - }, - { - "fid": 323, - "name": "잔존일수", - "offset": 20, - "start": 640 - }, - { - "fid": 403, - "name": "영업일기준잔존일", - "offset": 20, - "start": 660 - } - ], - "single_outputs_name": "선물전체시세", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "optfofid", - "tr_name": "FUTURE", - "tr_name_svr": "", - "tr_type": "1" - }, - "optkwfid": { - "gfid": "2001", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "관심종목정보요청", - "multi_outputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - }, - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 20 - }, - { - "fid": 10, - "name": "현재가", - "offset": 20, - "start": 120 - }, - { - "fid": 307, - "name": "기준가", - "offset": 20, - "start": 140 - }, - { - "fid": 11, - "name": "전일대비", - "offset": 20, - "start": 160 - }, - { - "fid": 25, - "name": "전일대비기호", - "offset": 20, - "start": 180 - }, - { - "fid": 12, - "name": "등락율", - "offset": 20, - "start": 200 - }, - { - "fid": 13, - "name": "거래량", - "offset": 20, - "start": 220 - }, - { - "fid": 14, - "name": "거래대금", - "offset": 20, - "start": 240 - }, - { - "fid": 15, - "name": "체결량", - "offset": 20, - "start": 260 - }, - { - "fid": 228, - "name": "체결강도", - "offset": 20, - "start": 280 - }, - { - "fid": 30, - "name": "전일거래량대비", - "offset": 20, - "start": 300 - }, - { - "fid": 27, - "name": "매도호가", - "offset": 20, - "start": 320 - }, - { - "fid": 28, - "name": "매수호가", - "offset": 20, - "start": 340 - }, - { - "fid": 41, - "name": "매도1차호가", - "offset": 20, - "start": 360 - }, - { - "fid": 42, - "name": "매도2차호가", - "offset": 20, - "start": 380 - }, - { - "fid": 43, - "name": "매도3차호가", - "offset": 20, - "start": 400 - }, - { - "fid": 44, - "name": "매도4차호가", - "offset": 20, - "start": 420 - }, - { - "fid": 45, - "name": "매도5차호가", - "offset": 20, - "start": 440 - }, - { - "fid": 51, - "name": "매수1차호가", - "offset": 20, - "start": 460 - }, - { - "fid": 52, - "name": "매수2차호가", - "offset": 20, - "start": 480 - }, - { - "fid": 53, - "name": "매수3차호가", - "offset": 20, - "start": 500 - }, - { - "fid": 54, - "name": "매수4차호가", - "offset": 20, - "start": 520 - }, - { - "fid": 55, - "name": "매수5차호가", - "offset": 20, - "start": 540 - }, - { - "fid": 305, - "name": "상한가", - "offset": 20, - "start": 560 - }, - { - "fid": 306, - "name": "하한가", - "offset": 20, - "start": 580 - }, - { - "fid": 16, - "name": "시가", - "offset": 20, - "start": 600 - }, - { - "fid": 17, - "name": "고가", - "offset": 20, - "start": 620 - }, - { - "fid": 18, - "name": "저가", - "offset": 20, - "start": 640 - }, - { - "fid": 10, - "name": "종가", - "offset": 20, - "start": 660 - }, - { - "fid": 20, - "name": "체결시간", - "offset": 20, - "start": 680 - }, - { - "fid": 23, - "name": "예상체결가", - "offset": 20, - "start": 700 - }, - { - "fid": 24, - "name": "예상체결량", - "offset": 20, - "start": 720 - }, - { - "fid": 309, - "name": "자본금", - "offset": 20, - "start": 740 - }, - { - "fid": 310, - "name": "액면가", - "offset": 20, - "start": 760 - }, - { - "fid": 311, - "name": "시가총액", - "offset": 20, - "start": 780 - }, - { - "fid": 312, - "name": "주식수", - "offset": 20, - "start": 800 - }, - { - "fid": 21, - "name": "호가시간", - "offset": 20, - "start": 820 - }, - { - "fid": 22, - "name": "일자", - "offset": 20, - "start": 840 - }, - { - "fid": 61, - "name": "우선매도잔량", - "offset": 20, - "start": 860 - }, - { - "fid": 71, - "name": "우선매수잔량", - "offset": 20, - "start": 880 - }, - { - "fid": 101, - "name": "우선매도건수", - "offset": 20, - "start": 900 - }, - { - "fid": 111, - "name": "우선매수건수", - "offset": 20, - "start": 920 - }, - { - "fid": 121, - "name": "총매도잔량", - "offset": 20, - "start": 940 - }, - { - "fid": 125, - "name": "총매수잔량", - "offset": 20, - "start": 960 - }, - { - "fid": 123, - "name": "총매도건수", - "offset": 20, - "start": 980 - }, - { - "fid": 127, - "name": "총매수건수", - "offset": 20, - "start": 1000 - }, - { - "fid": 666, - "name": "패리티", - "offset": 20, - "start": 1020 - }, - { - "fid": 667, - "name": "기어링", - "offset": 20, - "start": 1040 - }, - { - "fid": 668, - "name": "손익분기", - "offset": 20, - "start": 1060 - }, - { - "fid": 669, - "name": "자본지지", - "offset": 20, - "start": 1080 - }, - { - "fid": 425, - "name": "ELW행사가", - "offset": 20, - "start": 1100 - }, - { - "fid": 431, - "name": "전환비율", - "offset": 20, - "start": 1120 - }, - { - "fid": 372, - "name": "ELW만기일", - "offset": 20, - "start": 1140 - }, - { - "fid": 195, - "name": "미결제약정", - "offset": 20, - "start": 1160 - }, - { - "fid": 181, - "name": "미결제전일대비", - "offset": 20, - "start": 1180 - }, - { - "fid": 182, - "name": "이론가", - "offset": 20, - "start": 1200 - }, - { - "fid": 189, - "name": "내재변동성", - "offset": 20, - "start": 1220 - }, - { - "fid": 190, - "name": "델타", - "offset": 20, - "start": 1240 - }, - { - "fid": 191, - "name": "감마", - "offset": 20, - "start": 1260 - }, - { - "fid": 193, - "name": "쎄타", - "offset": 20, - "start": 1280 - }, - { - "fid": 192, - "name": "베가", - "offset": 20, - "start": 1300 - }, - { - "fid": 194, - "name": "로", - "offset": 20, - "start": 1320 - } - ], - "multi_outputs_name": "관심종목정보", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "optkwfid", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "optkwinv": { - "gfid": "2301", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "관심종목투자자정보요청", - "multi_outputs": [ - { - "fid": 302, - "name": "종목명", - "offset": 100, - "start": 0 - }, - { - "fid": 202, - "name": "매도수량", - "offset": 20, - "start": 100 - }, - { - "fid": 206, - "name": "매수수량", - "offset": 20, - "start": 120 - }, - { - "fid": 210, - "name": "순매수수량", - "offset": 20, - "start": 140 - }, - { - "fid": 204, - "name": "매도금액", - "offset": 20, - "start": 160 - }, - { - "fid": 208, - "name": "매수금액", - "offset": 20, - "start": 180 - }, - { - "fid": 212, - "name": "순매수금액", - "offset": 20, - "start": 200 - } - ], - "multi_outputs_name": "관심종목투자자정보", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "optkwinv", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "optkwpro": { - "gfid": "", - "inputs": [ - { - "fid": 9001, - "name": "종목코드", - "offset": 20, - "start": 0 - } - ], - "inputs_name": "관심종목프로그램정보요청", - "multi_outputs": [ - { - "fid": 502, - "name": "차익매도량", - "offset": 20, - "start": 0 - }, - { - "fid": 505, - "name": "차익매도대금", - "offset": 20, - "start": 20 - }, - { - "fid": 508, - "name": "차익매도비율", - "offset": 20, - "start": 40 - }, - { - "fid": 511, - "name": "차익매수량", - "offset": 20, - "start": 60 - }, - { - "fid": 514, - "name": "차익매수대금", - "offset": 20, - "start": 80 - }, - { - "fid": 517, - "name": "차익매수비율", - "offset": 20, - "start": 100 - }, - { - "fid": 522, - "name": "차익순매수금액", - "offset": 20, - "start": 120 - }, - { - "fid": 526, - "name": "비차익매도량", - "offset": 20, - "start": 140 - }, - { - "fid": 529, - "name": "비차익매도대금", - "offset": 20, - "start": 160 - }, - { - "fid": 532, - "name": "비차익매도비율", - "offset": 20, - "start": 180 - }, - { - "fid": 535, - "name": "비차익매수량", - "offset": 20, - "start": 200 - }, - { - "fid": 538, - "name": "비차익매수대금", - "offset": 20, - "start": 220 - }, - { - "fid": 541, - "name": "비차익매수비율", - "offset": 20, - "start": 240 - }, - { - "fid": 546, - "name": "비차익순매수금액", - "offset": 20, - "start": 260 - }, - { - "fid": 202, - "name": "합계매도량", - "offset": 20, - "start": 280 - }, - { - "fid": 204, - "name": "합계매도대금", - "offset": 20, - "start": 300 - }, - { - "fid": 206, - "name": "합계매수량", - "offset": 20, - "start": 320 - }, - { - "fid": 208, - "name": "합계매수대금", - "offset": 20, - "start": 340 - }, - { - "fid": 212, - "name": "합계순매수", - "offset": 20, - "start": 360 - } - ], - "multi_outputs_name": "관심종목프로그램정보", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "100", - "repeat_count_desc": "*" - }, - "single_outputs": [], - "single_outputs_name": "", - "single_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "tr_code": "optkwpro", - "tr_name": "STOCKG", - "tr_name_svr": "", - "tr_type": "1" - }, - "opw00001": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 76 - } - ], - "inputs_name": "예수금상세현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "통화코드", - "offset": 3, - "start": 1006 - }, - { - "fid": -1, - "name": "외화예수금", - "offset": 15, - "start": 1009 - }, - { - "fid": -1, - "name": "원화대용평가금", - "offset": 15, - "start": 1024 - }, - { - "fid": -1, - "name": "해외주식증거금", - "offset": 15, - "start": 1039 - }, - { - "fid": -1, - "name": "출금가능금액(예수금)", - "offset": 15, - "start": 1054 - }, - { - "fid": -1, - "name": "주문가능금액(예수금)", - "offset": 15, - "start": 1069 - }, - { - "fid": -1, - "name": "외화미수(합계)", - "offset": 15, - "start": 1084 - }, - { - "fid": -1, - "name": "외화현금미수금", - "offset": 15, - "start": 1099 - }, - { - "fid": -1, - "name": "연체료", - "offset": 15, - "start": 1114 - }, - { - "fid": -1, - "name": "d+1외화예수금", - "offset": 15, - "start": 1129 - }, - { - "fid": -1, - "name": "d+2외화예수금", - "offset": 15, - "start": 1144 - }, - { - "fid": -1, - "name": "d+3외화예수금", - "offset": 15, - "start": 1159 - }, - { - "fid": -1, - "name": "d+4외화예수금", - "offset": 15, - "start": 1174 - } - ], - "multi_outputs_name": "종목별예수금현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "예수금", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "주식증거금현금", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "수익증권증거금현금", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "익일수익증권매도정산대금", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "해외주식원화대용설정금", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "신용보증금현금", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "신용담보금현금", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "추가담보금현금", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "기타증거금", - "offset": 15, - "start": 120 - }, - { - "fid": -1, - "name": "미수확보금", - "offset": 15, - "start": 135 - }, - { - "fid": -1, - "name": "공매도대금", - "offset": 15, - "start": 150 - }, - { - "fid": -1, - "name": "신용설정평가금", - "offset": 15, - "start": 165 - }, - { - "fid": -1, - "name": "수표입금액", - "offset": 15, - "start": 180 - }, - { - "fid": -1, - "name": "기타수표입금액", - "offset": 15, - "start": 195 - }, - { - "fid": -1, - "name": "신용담보재사용", - "offset": 15, - "start": 210 - }, - { - "fid": -1, - "name": "코넥스기본예탁금", - "offset": 15, - "start": 225 - }, - { - "fid": -1, - "name": "ELW예탁평가금", - "offset": 15, - "start": 240 - }, - { - "fid": -1, - "name": "신용대주권리예정금액", - "offset": 15, - "start": 255 - }, - { - "fid": -1, - "name": "생계형가입금액", - "offset": 15, - "start": 270 - }, - { - "fid": -1, - "name": "생계형입금가능금액", - "offset": 15, - "start": 285 - }, - { - "fid": -1, - "name": "대용금평가금액(합계)", - "offset": 15, - "start": 300 - }, - { - "fid": -1, - "name": "잔고대용평가금액", - "offset": 15, - "start": 315 - }, - { - "fid": -1, - "name": "위탁대용잔고평가금액", - "offset": 15, - "start": 330 - }, - { - "fid": -1, - "name": "수익증권대용평가금액", - "offset": 15, - "start": 345 - }, - { - "fid": -1, - "name": "위탁증거금대용", - "offset": 15, - "start": 360 - }, - { - "fid": -1, - "name": "신용보증금대용", - "offset": 15, - "start": 375 - }, - { - "fid": -1, - "name": "신용담보금대용", - "offset": 15, - "start": 390 - }, - { - "fid": -1, - "name": "추가담보금대용", - "offset": 15, - "start": 405 - }, - { - "fid": -1, - "name": "권리대용금", - "offset": 15, - "start": 420 - }, - { - "fid": -1, - "name": "출금가능금액", - "offset": 15, - "start": 435 - }, - { - "fid": -1, - "name": "랩출금가능금액", - "offset": 15, - "start": 450 - }, - { - "fid": -1, - "name": "주문가능금액", - "offset": 15, - "start": 465 - }, - { - "fid": -1, - "name": "수익증권매수가능금액", - "offset": 15, - "start": 480 - }, - { - "fid": -1, - "name": "20%종목주문가능금액", - "offset": 15, - "start": 495 - }, - { - "fid": -1, - "name": "30%종목주문가능금액", - "offset": 15, - "start": 510 - }, - { - "fid": -1, - "name": "40%종목주문가능금액", - "offset": 15, - "start": 525 - }, - { - "fid": -1, - "name": "100%종목주문가능금액", - "offset": 15, - "start": 540 - }, - { - "fid": -1, - "name": "현금미수금", - "offset": 15, - "start": 555 - }, - { - "fid": -1, - "name": "현금미수연체료", - "offset": 15, - "start": 570 - }, - { - "fid": -1, - "name": "현금미수금합계", - "offset": 15, - "start": 585 - }, - { - "fid": -1, - "name": "신용이자미납", - "offset": 15, - "start": 600 - }, - { - "fid": -1, - "name": "신용이자미납연체료", - "offset": 15, - "start": 615 - }, - { - "fid": -1, - "name": "신용이자미납합계", - "offset": 15, - "start": 630 - }, - { - "fid": -1, - "name": "기타대여금", - "offset": 15, - "start": 645 - }, - { - "fid": -1, - "name": "기타대여금연체료", - "offset": 15, - "start": 660 - }, - { - "fid": -1, - "name": "기타대여금합계", - "offset": 15, - "start": 675 - }, - { - "fid": -1, - "name": "미상환융자금", - "offset": 15, - "start": 690 - }, - { - "fid": -1, - "name": "융자금합계", - "offset": 15, - "start": 705 - }, - { - "fid": -1, - "name": "대주금합계", - "offset": 15, - "start": 720 - }, - { - "fid": -1, - "name": "신용담보비율", - "offset": 12, - "start": 735 - }, - { - "fid": -1, - "name": "중도이용료", - "offset": 15, - "start": 747 - }, - { - "fid": -1, - "name": "최소주문가능금액", - "offset": 15, - "start": 762 - }, - { - "fid": -1, - "name": "대출총평가금액", - "offset": 15, - "start": 777 - }, - { - "fid": -1, - "name": "예탁담보대출잔고", - "offset": 15, - "start": 792 - }, - { - "fid": -1, - "name": "매도담보대출잔고", - "offset": 15, - "start": 807 - }, - { - "fid": -1, - "name": "d+1추정예수금", - "offset": 15, - "start": 822 - }, - { - "fid": -1, - "name": "d+1매도매수정산금", - "offset": 15, - "start": 837 - }, - { - "fid": -1, - "name": "d+1매수정산금", - "offset": 15, - "start": 852 - }, - { - "fid": -1, - "name": "d+1미수변제소요금", - "offset": 15, - "start": 867 - }, - { - "fid": -1, - "name": "d+1매도정산금", - "offset": 15, - "start": 882 - }, - { - "fid": -1, - "name": "d+1출금가능금액", - "offset": 15, - "start": 897 - }, - { - "fid": -1, - "name": "d+2추정예수금", - "offset": 15, - "start": 912 - }, - { - "fid": -1, - "name": "d+2매도매수정산금", - "offset": 15, - "start": 927 - }, - { - "fid": -1, - "name": "d+2매수정산금", - "offset": 15, - "start": 942 - }, - { - "fid": -1, - "name": "d+2미수변제소요금", - "offset": 15, - "start": 957 - }, - { - "fid": -1, - "name": "d+2매도정산금", - "offset": 15, - "start": 972 - }, - { - "fid": -1, - "name": "d+2출금가능금액", - "offset": 15, - "start": 987 - }, - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 1002 - } - ], - "single_outputs_name": "예수금상세현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00001", - "tr_name": "TTC2512_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00002": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "시작조회기간", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "종료조회기간", - "offset": 8, - "start": 82 - } - ], - "inputs_name": "일별추정예탁자산현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 8 - }, - { - "fid": -1, - "name": "담보대출금", - "offset": 12, - "start": 20 - }, - { - "fid": -1, - "name": "신용융자금", - "offset": 12, - "start": 32 - }, - { - "fid": -1, - "name": "대주담보금", - "offset": 12, - "start": 44 - }, - { - "fid": -1, - "name": "대용금", - "offset": 12, - "start": 56 - }, - { - "fid": -1, - "name": "추정예탁자산", - "offset": 12, - "start": 68 - }, - { - "fid": -1, - "name": "추정예탁자산수익증권제외", - "offset": 12, - "start": 80 - } - ], - "multi_outputs_name": "일별추정예탁자산현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00002", - "tr_name": "TME2005_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00003": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "상장폐지조회구분", - "offset": 1, - "start": 74 - } - ], - "inputs_name": "추정자산조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "추정예탁자산", - "offset": 12, - "start": 0 - } - ], - "single_outputs_name": "추정자산조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00003", - "tr_name": "TME2001_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00004": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "상장폐지조회구분", - "offset": 1, - "start": 74 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 75 - } - ], - "inputs_name": "계좌평가현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "종목명", - "offset": 30, - "start": 12 - }, - { - "fid": -1, - "name": "보유수량", - "offset": 12, - "start": 42 - }, - { - "fid": -1, - "name": "평균단가", - "offset": 12, - "start": 54 - }, - { - "fid": -1, - "name": "현재가", - "offset": 12, - "start": 66 - }, - { - "fid": -1, - "name": "평가금액", - "offset": 12, - "start": 78 - }, - { - "fid": -1, - "name": "손익금액", - "offset": 12, - "start": 90 - }, - { - "fid": -1, - "name": "손익율", - "offset": 12, - "start": 102 - }, - { - "fid": -1, - "name": "대출일", - "offset": 10, - "start": 114 - }, - { - "fid": -1, - "name": "매입금액", - "offset": 12, - "start": 124 - }, - { - "fid": -1, - "name": "결제잔고", - "offset": 12, - "start": 136 - }, - { - "fid": -1, - "name": "전일매수수량", - "offset": 12, - "start": 148 - }, - { - "fid": -1, - "name": "전일매도수량", - "offset": 12, - "start": 160 - }, - { - "fid": -1, - "name": "금일매수수량", - "offset": 12, - "start": 172 - }, - { - "fid": -1, - "name": "금일매도수량", - "offset": 12, - "start": 184 - } - ], - "multi_outputs_name": "종목별계좌평가현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "30", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "계좌명", - "offset": 30, - "start": 0 - }, - { - "fid": -1, - "name": "지점명", - "offset": 30, - "start": 30 - }, - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 60 - }, - { - "fid": -1, - "name": "D+2추정예수금", - "offset": 12, - "start": 72 - }, - { - "fid": -1, - "name": "유가잔고평가액", - "offset": 12, - "start": 84 - }, - { - "fid": -1, - "name": "예탁자산평가액", - "offset": 12, - "start": 96 - }, - { - "fid": -1, - "name": "총매입금액", - "offset": 12, - "start": 108 - }, - { - "fid": -1, - "name": "추정예탁자산", - "offset": 12, - "start": 120 - }, - { - "fid": -1, - "name": "매도담보대출금", - "offset": 12, - "start": 132 - }, - { - "fid": -1, - "name": "당일투자원금", - "offset": 12, - "start": 144 - }, - { - "fid": -1, - "name": "당월투자원금", - "offset": 12, - "start": 156 - }, - { - "fid": -1, - "name": "누적투자원금", - "offset": 12, - "start": 168 - }, - { - "fid": -1, - "name": "당일투자손익", - "offset": 12, - "start": 180 - }, - { - "fid": -1, - "name": "당월투자손익", - "offset": 12, - "start": 192 - }, - { - "fid": -1, - "name": "누적투자손익", - "offset": 12, - "start": 204 - }, - { - "fid": -1, - "name": "당일손익율", - "offset": 12, - "start": 216 - }, - { - "fid": -1, - "name": "당월손익율", - "offset": 12, - "start": 228 - }, - { - "fid": -1, - "name": "누적손익율", - "offset": 12, - "start": 240 - }, - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 252 - } - ], - "single_outputs_name": "계좌평가현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00004", - "tr_name": "TME2002_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00005": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "체결잔고요청", - "multi_outputs": [ - { - "fid": -1, - "name": "신용구분", - "offset": 2, - "start": 0 - }, - { - "fid": -1, - "name": "대출일", - "offset": 8, - "start": 2 - }, - { - "fid": -1, - "name": "만기일", - "offset": 8, - "start": 10 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 18 - }, - { - "fid": -1, - "name": "종목명", - "offset": 30, - "start": 30 - }, - { - "fid": -1, - "name": "결제잔고", - "offset": 12, - "start": 60 - }, - { - "fid": -1, - "name": "현재잔고", - "offset": 12, - "start": 72 - }, - { - "fid": -1, - "name": "현재가", - "offset": 12, - "start": 84 - }, - { - "fid": -1, - "name": "매입단가", - "offset": 12, - "start": 96 - }, - { - "fid": -1, - "name": "매입금액", - "offset": 12, - "start": 108 - }, - { - "fid": -1, - "name": "평가금액", - "offset": 12, - "start": 120 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 12, - "start": 132 - }, - { - "fid": -1, - "name": "손익률", - "offset": 12, - "start": 144 - } - ], - "multi_outputs_name": "종목별체결잔고", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "예수금D+1", - "offset": 12, - "start": 12 - }, - { - "fid": -1, - "name": "예수금D+2", - "offset": 12, - "start": 24 - }, - { - "fid": -1, - "name": "출금가능금액", - "offset": 12, - "start": 36 - }, - { - "fid": -1, - "name": "미수확보금", - "offset": 12, - "start": 48 - }, - { - "fid": -1, - "name": "대용금", - "offset": 12, - "start": 60 - }, - { - "fid": -1, - "name": "권리대용금", - "offset": 12, - "start": 72 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 12, - "start": 84 - }, - { - "fid": -1, - "name": "현금미수금", - "offset": 12, - "start": 96 - }, - { - "fid": -1, - "name": "신용이자미납금", - "offset": 12, - "start": 108 - }, - { - "fid": -1, - "name": "기타대여금", - "offset": 12, - "start": 120 - }, - { - "fid": -1, - "name": "미상환융자금", - "offset": 12, - "start": 132 - }, - { - "fid": -1, - "name": "증거금현금", - "offset": 12, - "start": 144 - }, - { - "fid": -1, - "name": "증거금대용", - "offset": 12, - "start": 156 - }, - { - "fid": -1, - "name": "주식매수총액", - "offset": 12, - "start": 168 - }, - { - "fid": -1, - "name": "평가금액합계", - "offset": 12, - "start": 180 - }, - { - "fid": -1, - "name": "총손익합계", - "offset": 12, - "start": 192 - }, - { - "fid": -1, - "name": "총손익률", - "offset": 12, - "start": 204 - }, - { - "fid": -1, - "name": "총재매수가능금액", - "offset": 12, - "start": 216 - }, - { - "fid": -1, - "name": "20주문가능금액", - "offset": 12, - "start": 228 - }, - { - "fid": -1, - "name": "30주문가능금액", - "offset": 12, - "start": 240 - }, - { - "fid": -1, - "name": "40주문가능금액", - "offset": 12, - "start": 252 - }, - { - "fid": -1, - "name": "50주문가능금액", - "offset": 12, - "start": 264 - }, - { - "fid": -1, - "name": "60주문가능금액", - "offset": 12, - "start": 276 - }, - { - "fid": -1, - "name": "100주문가능금액", - "offset": 12, - "start": 288 - }, - { - "fid": -1, - "name": "신용융자합계", - "offset": 12, - "start": 300 - }, - { - "fid": -1, - "name": "신용융자대주합계", - "offset": 12, - "start": 312 - }, - { - "fid": -1, - "name": "신용담보비율", - "offset": 12, - "start": 324 - }, - { - "fid": -1, - "name": "예탁담보대출금액", - "offset": 12, - "start": 336 - }, - { - "fid": -1, - "name": "매도담보대출금액", - "offset": 12, - "start": 348 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 360 - } - ], - "single_outputs_name": "체결잔고", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00005", - "tr_name": "TDA2601_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00006": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "지점코드", - "offset": 3, - "start": 8 - }, - { - "fid": -1, - "name": "시작주문번호", - "offset": 7, - "start": 11 - } - ], - "inputs_name": "관리자별주문체결내역요청", - "multi_outputs": [ - { - "fid": -1, - "name": "주문번호", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "원주문번호", - "offset": 7, - "start": 7 - }, - { - "fid": -1, - "name": "모주문번호", - "offset": 7, - "start": 14 - }, - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 21 - }, - { - "fid": -1, - "name": "계좌명", - "offset": 60, - "start": 31 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 91 - }, - { - "fid": -1, - "name": "정정구분", - "offset": 12, - "start": 103 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 4, - "start": 115 - }, - { - "fid": -1, - "name": "주문구분", - "offset": 12, - "start": 119 - }, - { - "fid": -1, - "name": "통신주문구분", - "offset": 8, - "start": 131 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 10, - "start": 139 - }, - { - "fid": -1, - "name": "주문지수", - "offset": 10, - "start": 149 - }, - { - "fid": -1, - "name": "주문잔량", - "offset": 10, - "start": 159 - }, - { - "fid": -1, - "name": "체결수량", - "offset": 10, - "start": 169 - }, - { - "fid": -1, - "name": "체결지수", - "offset": 10, - "start": 179 - }, - { - "fid": -1, - "name": "접수여부", - "offset": 10, - "start": 189 - }, - { - "fid": -1, - "name": "체결번호", - "offset": 7, - "start": 199 - } - ], - "multi_outputs_name": "관리자별주문체결내역", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00006", - "tr_name": "TDA2902_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00007": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "주문일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 8 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 18 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 82 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 84 - }, - { - "fid": -1, - "name": "주식채권구분", - "offset": 1, - "start": 85 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 1, - "start": 86 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 87 - }, - { - "fid": -1, - "name": "시작주문번호", - "offset": 7, - "start": 99 - } - ], - "inputs_name": "계좌별주문체결내역상세요청", - "multi_outputs": [ - { - "fid": -1, - "name": "주문번호", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 7 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 20, - "start": 19 - }, - { - "fid": -1, - "name": "신용구분", - "offset": 20, - "start": 39 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 10, - "start": 59 - }, - { - "fid": -1, - "name": "주문단가", - "offset": 10, - "start": 69 - }, - { - "fid": -1, - "name": "확인수량", - "offset": 10, - "start": 79 - }, - { - "fid": -1, - "name": "접수구분", - "offset": 20, - "start": 89 - }, - { - "fid": -1, - "name": "반대여부", - "offset": 20, - "start": 109 - }, - { - "fid": -1, - "name": "주문시간", - "offset": 8, - "start": 129 - }, - { - "fid": -1, - "name": "원주문", - "offset": 7, - "start": 137 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 144 - }, - { - "fid": -1, - "name": "주문구분", - "offset": 20, - "start": 184 - }, - { - "fid": -1, - "name": "대출일", - "offset": 8, - "start": 204 - }, - { - "fid": -1, - "name": "체결수량", - "offset": 10, - "start": 212 - }, - { - "fid": -1, - "name": "체결단가", - "offset": 10, - "start": 222 - }, - { - "fid": -1, - "name": "주문잔량", - "offset": 10, - "start": 232 - }, - { - "fid": -1, - "name": "통신구분", - "offset": 20, - "start": 242 - }, - { - "fid": -1, - "name": "정정취소", - "offset": 20, - "start": 262 - }, - { - "fid": -1, - "name": "확인시간", - "offset": 8, - "start": 282 - } - ], - "multi_outputs_name": "계좌별주문체결내역상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00007", - "tr_name": "TDA2931_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00008": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "시작결제번호", - "offset": 7, - "start": 76 - } - ], - "inputs_name": "계좌별익일결제예정내역요청", - "multi_outputs": [ - { - "fid": -1, - "name": "일련번호", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 7 - }, - { - "fid": -1, - "name": "대출일", - "offset": 8, - "start": 19 - }, - { - "fid": -1, - "name": "수량", - "offset": 12, - "start": 27 - }, - { - "fid": -1, - "name": "약정금액", - "offset": 12, - "start": 39 - }, - { - "fid": -1, - "name": "수수료", - "offset": 12, - "start": 51 - }, - { - "fid": -1, - "name": "소득세", - "offset": 12, - "start": 63 - }, - { - "fid": -1, - "name": "농특세", - "offset": 12, - "start": 75 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 87 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 10, - "start": 127 - }, - { - "fid": -1, - "name": "단가", - "offset": 12, - "start": 137 - }, - { - "fid": -1, - "name": "정산금액", - "offset": 12, - "start": 149 - }, - { - "fid": -1, - "name": "거래세", - "offset": 12, - "start": 161 - }, - { - "fid": -1, - "name": "주민세", - "offset": 12, - "start": 173 - }, - { - "fid": -1, - "name": "신용구분", - "offset": 20, - "start": 185 - } - ], - "multi_outputs_name": "계좌별익일결제예정내역배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "매매일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "결제일자", - "offset": 8, - "start": 8 - }, - { - "fid": -1, - "name": "매도정산합", - "offset": 12, - "start": 16 - }, - { - "fid": -1, - "name": "매수정산합", - "offset": 12, - "start": 28 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 40 - } - ], - "single_outputs_name": "계좌별익일결제예정내역", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00008", - "tr_name": "TDA3117_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00009": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "주문일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 8 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 18 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 82 - }, - { - "fid": -1, - "name": "주식채권구분", - "offset": 1, - "start": 84 - }, - { - "fid": -1, - "name": "시장구분", - "offset": 1, - "start": 85 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 1, - "start": 86 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 87 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 88 - }, - { - "fid": -1, - "name": "시작주문번호", - "offset": 7, - "start": 100 - } - ], - "inputs_name": "계좌별주문체결현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "주식채권구분", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "주문번호", - "offset": 7, - "start": 1 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 8 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 15, - "start": 20 - }, - { - "fid": -1, - "name": "주문유형구분", - "offset": 20, - "start": 35 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 10, - "start": 55 - }, - { - "fid": -1, - "name": "주문단가", - "offset": 10, - "start": 65 - }, - { - "fid": -1, - "name": "확인수량", - "offset": 10, - "start": 75 - }, - { - "fid": -1, - "name": "예약반대", - "offset": 4, - "start": 85 - }, - { - "fid": -1, - "name": "체결번호", - "offset": 7, - "start": 89 - }, - { - "fid": -1, - "name": "접수구분", - "offset": 8, - "start": 96 - }, - { - "fid": -1, - "name": "원주문번호", - "offset": 7, - "start": 104 - }, - { - "fid": -1, - "name": "종목명", - "offset": 20, - "start": 111 - }, - { - "fid": -1, - "name": "결제구분", - "offset": 8, - "start": 131 - }, - { - "fid": -1, - "name": "신용거래구분", - "offset": 20, - "start": 139 - }, - { - "fid": -1, - "name": "체결수량", - "offset": 10, - "start": 159 - }, - { - "fid": -1, - "name": "체결단가", - "offset": 10, - "start": 169 - }, - { - "fid": -1, - "name": "통신구분", - "offset": 8, - "start": 179 - }, - { - "fid": -1, - "name": "정정취소구분", - "offset": 12, - "start": 187 - }, - { - "fid": -1, - "name": "체결시간", - "offset": 8, - "start": 199 - } - ], - "multi_outputs_name": "계좌별주문체결현황배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "매도약정금액", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "매수약정금액", - "offset": 12, - "start": 12 - }, - { - "fid": -1, - "name": "약정금액", - "offset": 12, - "start": 24 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 36 - } - ], - "single_outputs_name": "계좌별주문체결현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00009", - "tr_name": "TDA2917_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00010": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "입출금액", - "offset": 12, - "start": 76 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 88 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 1, - "start": 100 - }, - { - "fid": -1, - "name": "매매수량", - "offset": 10, - "start": 101 - }, - { - "fid": -1, - "name": "매수가격", - "offset": 10, - "start": 111 - }, - { - "fid": -1, - "name": "예상매수단가", - "offset": 10, - "start": 121 - } - ], - "inputs_name": "주문인출가능금액요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "증거금20주문가능금액", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "증거금20주문가능수량", - "offset": 10, - "start": 12 - }, - { - "fid": -1, - "name": "증거금30주문가능금액", - "offset": 12, - "start": 22 - }, - { - "fid": -1, - "name": "증거금30주문가능수량", - "offset": 10, - "start": 34 - }, - { - "fid": -1, - "name": "증거금40주문가능금액", - "offset": 12, - "start": 44 - }, - { - "fid": -1, - "name": "증거금40주문가능수량", - "offset": 10, - "start": 56 - }, - { - "fid": -1, - "name": "증거금50주문가능금액", - "offset": 12, - "start": 66 - }, - { - "fid": -1, - "name": "증거금50주문가능수량", - "offset": 10, - "start": 78 - }, - { - "fid": -1, - "name": "증거금60주문가능금액", - "offset": 12, - "start": 88 - }, - { - "fid": -1, - "name": "증거금60주문가능수량", - "offset": 10, - "start": 100 - }, - { - "fid": -1, - "name": "증거금감면60주문가능금", - "offset": 12, - "start": 110 - }, - { - "fid": -1, - "name": "증거금감면60주문가능수", - "offset": 10, - "start": 122 - }, - { - "fid": -1, - "name": "증거금100주문가능금액", - "offset": 12, - "start": 132 - }, - { - "fid": -1, - "name": "증거금100주문가능수량", - "offset": 10, - "start": 144 - }, - { - "fid": -1, - "name": "전일재사용가능금액", - "offset": 12, - "start": 154 - }, - { - "fid": -1, - "name": "금일재사용가능금액", - "offset": 12, - "start": 166 - }, - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 178 - }, - { - "fid": -1, - "name": "대용금", - "offset": 12, - "start": 190 - }, - { - "fid": -1, - "name": "미수금", - "offset": 12, - "start": 202 - }, - { - "fid": -1, - "name": "주문가능대용", - "offset": 12, - "start": 214 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 12, - "start": 226 - }, - { - "fid": -1, - "name": "인출가능금액", - "offset": 12, - "start": 238 - }, - { - "fid": -1, - "name": "익일인출가능금액", - "offset": 12, - "start": 250 - }, - { - "fid": -1, - "name": "매입금액", - "offset": 12, - "start": 262 - }, - { - "fid": -1, - "name": "수수료", - "offset": 12, - "start": 274 - }, - { - "fid": -1, - "name": "매입정산금", - "offset": 12, - "start": 286 - }, - { - "fid": -1, - "name": "D2추정예수금", - "offset": 12, - "start": 298 - }, - { - "fid": -1, - "name": "증거금감면적용구분", - "offset": 1, - "start": 310 - } - ], - "single_outputs_name": "주문인출가능금액", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00010", - "tr_name": "TDA2808_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00011": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 76 - }, - { - "fid": -1, - "name": "매수가격", - "offset": 10, - "start": 88 - } - ], - "inputs_name": "증거금율별주문가능수량조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "종목증거금율", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "계좌증거금율", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "적용증거금율", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "증거금20주문가능금액", - "offset": 12, - "start": 45 - }, - { - "fid": -1, - "name": "증거금20주문가능수량", - "offset": 12, - "start": 57 - }, - { - "fid": -1, - "name": "증거금20전일재사용금액", - "offset": 12, - "start": 69 - }, - { - "fid": -1, - "name": "증거금20금일재사용금액", - "offset": 12, - "start": 81 - }, - { - "fid": -1, - "name": "증거금30주문가능금액", - "offset": 12, - "start": 93 - }, - { - "fid": -1, - "name": "증거금30주문가능수량", - "offset": 12, - "start": 105 - }, - { - "fid": -1, - "name": "증거금30전일재사용금액", - "offset": 12, - "start": 117 - }, - { - "fid": -1, - "name": "증거금30금일재사용금액", - "offset": 12, - "start": 129 - }, - { - "fid": -1, - "name": "증거금40주문가능금액", - "offset": 12, - "start": 141 - }, - { - "fid": -1, - "name": "증거금40주문가능수량", - "offset": 12, - "start": 153 - }, - { - "fid": -1, - "name": "증거금40전일재사용금액", - "offset": 12, - "start": 165 - }, - { - "fid": -1, - "name": "증거금40금일재사용금액", - "offset": 12, - "start": 177 - }, - { - "fid": -1, - "name": "증거금50주문가능금액", - "offset": 12, - "start": 189 - }, - { - "fid": -1, - "name": "증거금50주문가능수량", - "offset": 12, - "start": 201 - }, - { - "fid": -1, - "name": "증거금50전일재사용금액", - "offset": 12, - "start": 213 - }, - { - "fid": -1, - "name": "증거금50금일재사용금액", - "offset": 12, - "start": 225 - }, - { - "fid": -1, - "name": "증거금60주문가능금액", - "offset": 12, - "start": 237 - }, - { - "fid": -1, - "name": "증거금60주문가능수량", - "offset": 12, - "start": 249 - }, - { - "fid": -1, - "name": "증거금60전일재사용금액", - "offset": 12, - "start": 261 - }, - { - "fid": -1, - "name": "증거금60금일재사용금액", - "offset": 12, - "start": 273 - }, - { - "fid": -1, - "name": "증거금100주문가능금액", - "offset": 12, - "start": 285 - }, - { - "fid": -1, - "name": "증거금100주문가능수량", - "offset": 12, - "start": 297 - }, - { - "fid": -1, - "name": "증거금100전일재사용금액", - "offset": 12, - "start": 309 - }, - { - "fid": -1, - "name": "증거금100금일재사용금액", - "offset": 12, - "start": 321 - }, - { - "fid": -1, - "name": "미수불가주문가능금액", - "offset": 12, - "start": 333 - }, - { - "fid": -1, - "name": "미수불가주문가능수량", - "offset": 12, - "start": 345 - }, - { - "fid": -1, - "name": "미수불가전일재사용금액", - "offset": 12, - "start": 357 - }, - { - "fid": -1, - "name": "미수불가금일재사용금액", - "offset": 12, - "start": 369 - }, - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 381 - }, - { - "fid": -1, - "name": "대용금", - "offset": 12, - "start": 393 - }, - { - "fid": -1, - "name": "미수금", - "offset": 12, - "start": 405 - }, - { - "fid": -1, - "name": "주문가능대용", - "offset": 12, - "start": 417 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 12, - "start": 429 - } - ], - "single_outputs_name": "증거금율별주문가능수량조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00011", - "tr_name": "TDA2806_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00012": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 76 - }, - { - "fid": -1, - "name": "매수가격", - "offset": 10, - "start": 88 - } - ], - "inputs_name": "신용보증금율별주문가능수량조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "종목보증금율", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "종목보증금율명", - "offset": 4, - "start": 1 - }, - { - "fid": -1, - "name": "보증금30주문가능금액", - "offset": 12, - "start": 5 - }, - { - "fid": -1, - "name": "보증금30주문가능수량", - "offset": 12, - "start": 17 - }, - { - "fid": -1, - "name": "보증금30전일재사용금액", - "offset": 12, - "start": 29 - }, - { - "fid": -1, - "name": "보증금30금일재사용금액", - "offset": 12, - "start": 41 - }, - { - "fid": -1, - "name": "보증금40주문가능금액", - "offset": 12, - "start": 53 - }, - { - "fid": -1, - "name": "보증금40주문가능수량", - "offset": 12, - "start": 65 - }, - { - "fid": -1, - "name": "보증금40전일재사용금액", - "offset": 12, - "start": 77 - }, - { - "fid": -1, - "name": "보증금40금일재사용금액", - "offset": 12, - "start": 89 - }, - { - "fid": -1, - "name": "보증금50주문가능금액", - "offset": 12, - "start": 101 - }, - { - "fid": -1, - "name": "보증금50주문가능수량", - "offset": 12, - "start": 113 - }, - { - "fid": -1, - "name": "보증금50전일재사용금액", - "offset": 12, - "start": 125 - }, - { - "fid": -1, - "name": "보증금50금일재사용금액", - "offset": 12, - "start": 137 - }, - { - "fid": -1, - "name": "보증금60주문가능금액", - "offset": 12, - "start": 149 - }, - { - "fid": -1, - "name": "보증금60주문가능수량", - "offset": 12, - "start": 161 - }, - { - "fid": -1, - "name": "보증금60전일재사용금액", - "offset": 12, - "start": 173 - }, - { - "fid": -1, - "name": "보증금60금일재사용금액", - "offset": 12, - "start": 185 - }, - { - "fid": -1, - "name": "예수금", - "offset": 12, - "start": 197 - }, - { - "fid": -1, - "name": "대용금", - "offset": 12, - "start": 209 - }, - { - "fid": -1, - "name": "미수금", - "offset": 12, - "start": 221 - }, - { - "fid": -1, - "name": "주문가능대용", - "offset": 12, - "start": 233 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 12, - "start": 245 - }, - { - "fid": -1, - "name": "미수가능금액", - "offset": 12, - "start": 257 - }, - { - "fid": -1, - "name": "미수가능수량", - "offset": 12, - "start": 269 - }, - { - "fid": -1, - "name": "미수불가금액", - "offset": 12, - "start": 281 - }, - { - "fid": -1, - "name": "미수불가수량", - "offset": 12, - "start": 293 - } - ], - "single_outputs_name": "신용보증금율별주문가능수량조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00012", - "tr_name": "TDA2810_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00013": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - } - ], - "inputs_name": "증거금세부내역조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "금일재사용대상금액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "금일재사용사용금액", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "금일재사용가능금액", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "금일재사용제한금액", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "금일재사용가능금액최종", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "전일재사용대상금액", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "전일재사용사용금액", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "전일재사용가능금액", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "전일재사용제한금액", - "offset": 15, - "start": 120 - }, - { - "fid": -1, - "name": "전일재사용가능금액최종", - "offset": 15, - "start": 135 - }, - { - "fid": -1, - "name": "현금금액", - "offset": 15, - "start": 150 - }, - { - "fid": -1, - "name": "현금증거금", - "offset": 15, - "start": 165 - }, - { - "fid": -1, - "name": "사용가능현금", - "offset": 15, - "start": 180 - }, - { - "fid": -1, - "name": "현금사용제한금액", - "offset": 15, - "start": 195 - }, - { - "fid": -1, - "name": "사용가능현금최종", - "offset": 15, - "start": 210 - }, - { - "fid": -1, - "name": "대용금액", - "offset": 15, - "start": 225 - }, - { - "fid": -1, - "name": "대용증거금", - "offset": 15, - "start": 240 - }, - { - "fid": -1, - "name": "사용가능대용", - "offset": 15, - "start": 255 - }, - { - "fid": -1, - "name": "대용사용제한금액", - "offset": 15, - "start": 270 - }, - { - "fid": -1, - "name": "사용가능대용최종", - "offset": 15, - "start": 285 - }, - { - "fid": -1, - "name": "신용보증금현금", - "offset": 15, - "start": 300 - }, - { - "fid": -1, - "name": "신용보증금대용", - "offset": 15, - "start": 315 - }, - { - "fid": -1, - "name": "신용담보금현금", - "offset": 15, - "start": 330 - }, - { - "fid": -1, - "name": "신용담보금대용", - "offset": 15, - "start": 345 - }, - { - "fid": -1, - "name": "미수금", - "offset": 12, - "start": 360 - }, - { - "fid": -1, - "name": "대주담보금재사용금", - "offset": 15, - "start": 372 - }, - { - "fid": -1, - "name": "20주문가능금액", - "offset": 15, - "start": 387 - }, - { - "fid": -1, - "name": "30주문가능금액", - "offset": 15, - "start": 402 - }, - { - "fid": -1, - "name": "40주문가능금액", - "offset": 15, - "start": 417 - }, - { - "fid": -1, - "name": "50주문가능금액", - "offset": 15, - "start": 432 - }, - { - "fid": -1, - "name": "60주문가능금액", - "offset": 15, - "start": 447 - }, - { - "fid": -1, - "name": "100주문가능금액", - "offset": 15, - "start": 462 - }, - { - "fid": -1, - "name": "금일신용상환손실금액", - "offset": 15, - "start": 477 - }, - { - "fid": -1, - "name": "전일신용상환손실금액", - "offset": 15, - "start": 492 - }, - { - "fid": -1, - "name": "금일대주상환손실대용증거금", - "offset": 15, - "start": 507 - }, - { - "fid": -1, - "name": "전일대주상환손실대용증거금", - "offset": 15, - "start": 522 - }, - { - "fid": -1, - "name": "평가대용금(현물사용제외)", - "offset": 15, - "start": 537 - }, - { - "fid": -1, - "name": "평가대용비율", - "offset": 15, - "start": 552 - }, - { - "fid": -1, - "name": "신용대용증거금", - "offset": 15, - "start": 567 - }, - { - "fid": -1, - "name": "현금주문대용증거금", - "offset": 15, - "start": 582 - }, - { - "fid": -1, - "name": "신용주문대용증거금", - "offset": 15, - "start": 597 - }, - { - "fid": -1, - "name": "신용대용환산금", - "offset": 15, - "start": 612 - }, - { - "fid": -1, - "name": "대용가능금액", - "offset": 15, - "start": 627 - }, - { - "fid": -1, - "name": "대용가능금액2", - "offset": 15, - "start": 642 - }, - { - "fid": -1, - "name": "현금대용부족금", - "offset": 15, - "start": 657 - }, - { - "fid": -1, - "name": "신용대용부족금", - "offset": 15, - "start": 672 - }, - { - "fid": -1, - "name": "현금주문가능대용금", - "offset": 15, - "start": 687 - }, - { - "fid": -1, - "name": "신용주문가능대용금", - "offset": 15, - "start": 702 - } - ], - "single_outputs_name": "증거금세부내역조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00013", - "tr_name": "TDA2303_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00014": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "비밀번호일치여부요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "일치여부", - "offset": 1, - "start": 0 - } - ], - "single_outputs_name": "비밀번호일치여부", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00014", - "tr_name": "TCA4551_Q64", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00015": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "시작일자", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "종료일자", - "offset": 8, - "start": 82 - }, - { - "fid": -1, - "name": "구분", - "offset": 1, - "start": 90 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 91 - }, - { - "fid": -1, - "name": "통화코드", - "offset": 3, - "start": 103 - }, - { - "fid": -1, - "name": "상품구분", - "offset": 1, - "start": 106 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 107 - }, - { - "fid": -1, - "name": "고객정보제한여부", - "offset": 1, - "start": 109 - } - ], - "inputs_name": "위탁종합거래내역요청", - "multi_outputs": [ - { - "fid": -1, - "name": "거래일자", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "거래번호", - "offset": 9, - "start": 8 - }, - { - "fid": -1, - "name": "적요명", - "offset": 60, - "start": 17 - }, - { - "fid": -1, - "name": "신용거래구분명", - "offset": 20, - "start": 77 - }, - { - "fid": -1, - "name": "정산금액", - "offset": 15, - "start": 97 - }, - { - "fid": -1, - "name": "대출금상환", - "offset": 15, - "start": 112 - }, - { - "fid": -1, - "name": "거래금액(외)", - "offset": 15, - "start": 127 - }, - { - "fid": -1, - "name": "정산금액(외)", - "offset": 15, - "start": 142 - }, - { - "fid": -1, - "name": "예수금잔고", - "offset": 15, - "start": 157 - }, - { - "fid": -1, - "name": "통화코드", - "offset": 3, - "start": 172 - }, - { - "fid": -1, - "name": "거래종류구분", - "offset": 2, - "start": 175 - }, - { - "fid": -1, - "name": "거래종류명", - "offset": 20, - "start": 177 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 197 - }, - { - "fid": -1, - "name": "거래금액", - "offset": 15, - "start": 237 - }, - { - "fid": -1, - "name": "거래및농특세", - "offset": 15, - "start": 252 - }, - { - "fid": -1, - "name": "상환차금", - "offset": 15, - "start": 267 - }, - { - "fid": -1, - "name": "거래세(외)", - "offset": 15, - "start": 282 - }, - { - "fid": -1, - "name": "연체합", - "offset": 15, - "start": 297 - }, - { - "fid": -1, - "name": "외화예수금잔고", - "offset": 15, - "start": 312 - }, - { - "fid": -1, - "name": "매체구분명", - "offset": 20, - "start": 327 - }, - { - "fid": -1, - "name": "입출구분", - "offset": 1, - "start": 347 - }, - { - "fid": -1, - "name": "입출구분명", - "offset": 10, - "start": 348 - }, - { - "fid": -1, - "name": "원거래번호", - "offset": 9, - "start": 358 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 367 - }, - { - "fid": -1, - "name": "거래수량/좌수", - "offset": 30, - "start": 379 - }, - { - "fid": -1, - "name": "수수료", - "offset": 15, - "start": 394 - }, - { - "fid": -1, - "name": "이자/대주이용", - "offset": 15, - "start": 409 - }, - { - "fid": -1, - "name": "수수료(외)", - "offset": 15, - "start": 424 - }, - { - "fid": -1, - "name": "연체합(외)", - "offset": 15, - "start": 439 - }, - { - "fid": -1, - "name": "유가금잔", - "offset": 30, - "start": 454 - }, - { - "fid": -1, - "name": "처리시간", - "offset": 111, - "start": 469 - }, - { - "fid": -1, - "name": "ISIN코드", - "offset": 12, - "start": 580 - }, - { - "fid": -1, - "name": "거래소코드", - "offset": 10, - "start": 592 - }, - { - "fid": -1, - "name": "거래소명", - "offset": 20, - "start": 602 - }, - { - "fid": -1, - "name": "거래단가/환율", - "offset": 20, - "start": 622 - }, - { - "fid": -1, - "name": "소득/주민세", - "offset": 15, - "start": 642 - }, - { - "fid": -1, - "name": "대출일", - "offset": 8, - "start": 657 - }, - { - "fid": -1, - "name": "미수(원/주)", - "offset": 30, - "start": 665 - }, - { - "fid": -1, - "name": "변제합", - "offset": 15, - "start": 680 - }, - { - "fid": -1, - "name": "체결일", - "offset": 8, - "start": 695 - }, - { - "fid": -1, - "name": "출납번호", - "offset": 20, - "start": 703 - }, - { - "fid": -1, - "name": "처리자", - "offset": 20, - "start": 723 - }, - { - "fid": -1, - "name": "처리점", - "offset": 20, - "start": 743 - }, - { - "fid": -1, - "name": "매매형태", - "offset": 40, - "start": 763 - }, - { - "fid": -1, - "name": "과세기준가", - "offset": 15, - "start": 803 - }, - { - "fid": -1, - "name": "세금수수료합", - "offset": 15, - "start": 818 - }, - { - "fid": -1, - "name": "외국납부세액(외)", - "offset": 15, - "start": 833 - }, - { - "fid": -1, - "name": "미수(외)", - "offset": 15, - "start": 848 - }, - { - "fid": -1, - "name": "변제합(외)", - "offset": 30, - "start": 863 - }, - { - "fid": -1, - "name": "입금자", - "offset": 20, - "start": 878 - }, - { - "fid": -1, - "name": "거래내역구분", - "offset": 2, - "start": 898 - } - ], - "multi_outputs_name": "위탁종합거래내역배열", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 62, - "start": 0 - }, - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 62 - } - ], - "single_outputs_name": "위탁종합거래내역", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00015", - "tr_name": "TTC5020_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00016": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "평가시작일", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "평가종료일", - "offset": 8, - "start": 82 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 90 - } - ], - "inputs_name": "일별계좌수익률상세현황요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "관리사원번호", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "관리자명", - "offset": 30, - "start": 8 - }, - { - "fid": -1, - "name": "관리자지점", - "offset": 30, - "start": 38 - }, - { - "fid": -1, - "name": "예수금_초", - "offset": 12, - "start": 68 - }, - { - "fid": -1, - "name": "예수금_말", - "offset": 12, - "start": 80 - }, - { - "fid": -1, - "name": "유가증권평가금액_초", - "offset": 12, - "start": 92 - }, - { - "fid": -1, - "name": "유가증권평가금액_말", - "offset": 12, - "start": 104 - }, - { - "fid": -1, - "name": "대주담보금_초", - "offset": 12, - "start": 116 - }, - { - "fid": -1, - "name": "대주담보금_말", - "offset": 12, - "start": 128 - }, - { - "fid": -1, - "name": "신용융자금_초", - "offset": 12, - "start": 140 - }, - { - "fid": -1, - "name": "신용융자금_말", - "offset": 12, - "start": 152 - }, - { - "fid": -1, - "name": "현금미수금_초", - "offset": 12, - "start": 164 - }, - { - "fid": -1, - "name": "현금미수금_말", - "offset": 12, - "start": 176 - }, - { - "fid": -1, - "name": "원화대용금_초", - "offset": 12, - "start": 188 - }, - { - "fid": -1, - "name": "원화대용금_말", - "offset": 12, - "start": 200 - }, - { - "fid": -1, - "name": "대주평가금_초", - "offset": 12, - "start": 212 - }, - { - "fid": -1, - "name": "대주평가금_말", - "offset": 12, - "start": 224 - }, - { - "fid": -1, - "name": "권리평가금_초", - "offset": 12, - "start": 236 - }, - { - "fid": -1, - "name": "권리평가금_말", - "offset": 12, - "start": 248 - }, - { - "fid": -1, - "name": "대출금_초", - "offset": 12, - "start": 260 - }, - { - "fid": -1, - "name": "대출금_말", - "offset": 12, - "start": 272 - }, - { - "fid": -1, - "name": "기타대여금_초", - "offset": 12, - "start": 284 - }, - { - "fid": -1, - "name": "기타대여금_말", - "offset": 12, - "start": 296 - }, - { - "fid": -1, - "name": "신용이자미납금_초", - "offset": 12, - "start": 308 - }, - { - "fid": -1, - "name": "신용이자미납금_말", - "offset": 12, - "start": 320 - }, - { - "fid": -1, - "name": "신용이자_초", - "offset": 12, - "start": 332 - }, - { - "fid": -1, - "name": "신용이자_말", - "offset": 12, - "start": 344 - }, - { - "fid": -1, - "name": "순자산액계_초", - "offset": 12, - "start": 356 - }, - { - "fid": -1, - "name": "순자산액계_말", - "offset": 12, - "start": 368 - }, - { - "fid": -1, - "name": "투자원금평잔", - "offset": 12, - "start": 380 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 12, - "start": 392 - }, - { - "fid": -1, - "name": "수익률", - "offset": 12, - "start": 404 - }, - { - "fid": -1, - "name": "회전율", - "offset": 12, - "start": 416 - }, - { - "fid": -1, - "name": "기간내총입금", - "offset": 12, - "start": 428 - }, - { - "fid": -1, - "name": "기간내총출금", - "offset": 12, - "start": 440 - }, - { - "fid": -1, - "name": "기간내총입고", - "offset": 12, - "start": 452 - }, - { - "fid": -1, - "name": "기간내총출고", - "offset": 12, - "start": 464 - }, - { - "fid": -1, - "name": "선물대용매도금액", - "offset": 12, - "start": 476 - }, - { - "fid": -1, - "name": "위탁대용매도금액", - "offset": 12, - "start": 488 - } - ], - "single_outputs_name": "일별계좌수익률상세현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00016", - "tr_name": "TME3001_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00017": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "계좌별당일현황요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "D+2추정예수금", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "신용이자미납금", - "offset": 12, - "start": 12 - }, - { - "fid": -1, - "name": "기타대여금", - "offset": 12, - "start": 24 - }, - { - "fid": -1, - "name": "일반주식평가금액D+2", - "offset": 12, - "start": 36 - }, - { - "fid": -1, - "name": "예탁담보대출금D+2", - "offset": 12, - "start": 48 - }, - { - "fid": -1, - "name": "예탁담보주식평가금액D+2", - "offset": 12, - "start": 60 - }, - { - "fid": -1, - "name": "신용융자금D+2", - "offset": 12, - "start": 72 - }, - { - "fid": -1, - "name": "신용융자평가금D+2", - "offset": 12, - "start": 84 - }, - { - "fid": -1, - "name": "신용대주담보금D+2", - "offset": 12, - "start": 96 - }, - { - "fid": -1, - "name": "신용대주평가금D+2", - "offset": 12, - "start": 108 - }, - { - "fid": -1, - "name": "입금금액", - "offset": 12, - "start": 120 - }, - { - "fid": -1, - "name": "출금금액", - "offset": 12, - "start": 132 - }, - { - "fid": -1, - "name": "입고금액", - "offset": 12, - "start": 144 - }, - { - "fid": -1, - "name": "출고금액", - "offset": 12, - "start": 156 - }, - { - "fid": -1, - "name": "매도금액", - "offset": 12, - "start": 168 - }, - { - "fid": -1, - "name": "매수금액", - "offset": 12, - "start": 180 - }, - { - "fid": -1, - "name": "수수료", - "offset": 12, - "start": 192 - }, - { - "fid": -1, - "name": "세금", - "offset": 12, - "start": 204 - }, - { - "fid": -1, - "name": "주식매입자금대출금", - "offset": 12, - "start": 216 - }, - { - "fid": -1, - "name": "RP평가금액", - "offset": 12, - "start": 228 - }, - { - "fid": -1, - "name": "채권평가금액", - "offset": 12, - "start": 240 - }, - { - "fid": -1, - "name": "ELS평가금액", - "offset": 12, - "start": 252 - }, - { - "fid": -1, - "name": "신용이자금액", - "offset": 12, - "start": 264 - }, - { - "fid": -1, - "name": "매도대금담보대출이자금액", - "offset": 12, - "start": 276 - }, - { - "fid": -1, - "name": "배당금액", - "offset": 12, - "start": 288 - } - ], - "single_outputs_name": "계좌별당일현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00017", - "tr_name": "TDA2507_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw00018": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 76 - } - ], - "inputs_name": "계좌평가잔고내역요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 12 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 15, - "start": 52 - }, - { - "fid": -1, - "name": "수익률(%)", - "offset": 12, - "start": 67 - }, - { - "fid": -1, - "name": "매입가", - "offset": 15, - "start": 79 - }, - { - "fid": -1, - "name": "전일종가", - "offset": 12, - "start": 94 - }, - { - "fid": -1, - "name": "보유수량", - "offset": 15, - "start": 106 - }, - { - "fid": -1, - "name": "매매가능수량", - "offset": 15, - "start": 121 - }, - { - "fid": -1, - "name": "현재가", - "offset": 12, - "start": 136 - }, - { - "fid": -1, - "name": "전일매수수량", - "offset": 15, - "start": 148 - }, - { - "fid": -1, - "name": "전일매도수량", - "offset": 15, - "start": 163 - }, - { - "fid": -1, - "name": "금일매수수량", - "offset": 15, - "start": 178 - }, - { - "fid": -1, - "name": "금일매도수량", - "offset": 15, - "start": 193 - }, - { - "fid": -1, - "name": "매입금액", - "offset": 15, - "start": 208 - }, - { - "fid": -1, - "name": "매입수수료", - "offset": 15, - "start": 223 - }, - { - "fid": -1, - "name": "평가금액", - "offset": 15, - "start": 238 - }, - { - "fid": -1, - "name": "평가수수료", - "offset": 15, - "start": 253 - }, - { - "fid": -1, - "name": "세금", - "offset": 15, - "start": 268 - }, - { - "fid": -1, - "name": "수수료합", - "offset": 15, - "start": 283 - }, - { - "fid": -1, - "name": "보유비중(%)", - "offset": 12, - "start": 298 - }, - { - "fid": -1, - "name": "신용구분", - "offset": 2, - "start": 310 - }, - { - "fid": -1, - "name": "신용구분명", - "offset": 4, - "start": 312 - }, - { - "fid": -1, - "name": "대출일", - "offset": 8, - "start": 316 - } - ], - "multi_outputs_name": "계좌평가잔고개별합산", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "총매입금액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "총평가금액", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "총평가손익금액", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "총수익률(%)", - "offset": 12, - "start": 45 - }, - { - "fid": -1, - "name": "추정예탁자산", - "offset": 15, - "start": 57 - }, - { - "fid": -1, - "name": "총대출금", - "offset": 15, - "start": 72 - }, - { - "fid": -1, - "name": "총융자금액", - "offset": 15, - "start": 87 - }, - { - "fid": -1, - "name": "총대주금액", - "offset": 15, - "start": 102 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 117 - } - ], - "single_outputs_name": "계좌평가결과", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw00018", - "tr_name": "TDA2602_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw20001": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "입력건수", - "offset": 4, - "start": 74 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 78 - }, - { - "fid": -1, - "name": "매수매도구분", - "offset": 1, - "start": 86 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 12, - "start": 87 - }, - { - "fid": -1, - "name": "잔고수량", - "offset": 12, - "start": 99 - } - ], - "inputs_name": "선물옵션청산주문위탁증거금가계산요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "현재위탁증거금총액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "현재현금예탁필요액", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "체결위탁증거금총액", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "체결현금예탁필요액", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "증감위탁증거금총액", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "증감현금예탁필요액", - "offset": 15, - "start": 75 - } - ], - "single_outputs_name": "선옵위탁증거금가계산", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20001", - "tr_name": "TDB1005_Q06", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20002": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "시장구분", - "offset": 1, - "start": 74 - }, - { - "fid": -1, - "name": "체결일자", - "offset": 8, - "start": 75 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 83 - } - ], - "inputs_name": "선옵당일매매변동현황요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "선물수수료", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "옵션수수료", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "주식옵션수수료", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "선물매도수량", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "선물매도금액", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "선물매도평균가격", - "offset": 9, - "start": 75 - }, - { - "fid": -1, - "name": "선물매수수량", - "offset": 15, - "start": 84 - }, - { - "fid": -1, - "name": "선물매수금액", - "offset": 15, - "start": 99 - }, - { - "fid": -1, - "name": "선물매수평균가격", - "offset": 9, - "start": 114 - }, - { - "fid": -1, - "name": "선물전매수량", - "offset": 15, - "start": 123 - }, - { - "fid": -1, - "name": "선물전매금액", - "offset": 15, - "start": 138 - }, - { - "fid": -1, - "name": "선물환매수량", - "offset": 15, - "start": 153 - }, - { - "fid": -1, - "name": "선물환매금액", - "offset": 15, - "start": 168 - }, - { - "fid": -1, - "name": "콜매도수량", - "offset": 15, - "start": 183 - }, - { - "fid": -1, - "name": "콜매도금액", - "offset": 15, - "start": 198 - }, - { - "fid": -1, - "name": "콜매도평균가격", - "offset": 9, - "start": 213 - }, - { - "fid": -1, - "name": "콜매수수량", - "offset": 15, - "start": 222 - }, - { - "fid": -1, - "name": "콜매수금액", - "offset": 15, - "start": 237 - }, - { - "fid": -1, - "name": "콜매수평균가격", - "offset": 9, - "start": 252 - }, - { - "fid": -1, - "name": "콜전매수량", - "offset": 15, - "start": 261 - }, - { - "fid": -1, - "name": "콜전매금액", - "offset": 15, - "start": 276 - }, - { - "fid": -1, - "name": "콜환매수량", - "offset": 15, - "start": 291 - }, - { - "fid": -1, - "name": "콜환매금액", - "offset": 15, - "start": 306 - }, - { - "fid": -1, - "name": "풋매도수량", - "offset": 15, - "start": 321 - }, - { - "fid": -1, - "name": "풋매도금액", - "offset": 15, - "start": 336 - }, - { - "fid": -1, - "name": "풋매도평균가격", - "offset": 9, - "start": 351 - }, - { - "fid": -1, - "name": "풋매수수량", - "offset": 15, - "start": 360 - }, - { - "fid": -1, - "name": "풋매수금액", - "offset": 15, - "start": 375 - }, - { - "fid": -1, - "name": "풋매수평균가격", - "offset": 9, - "start": 390 - }, - { - "fid": -1, - "name": "풋전매수량", - "offset": 15, - "start": 399 - }, - { - "fid": -1, - "name": "풋전매금액", - "offset": 15, - "start": 414 - }, - { - "fid": -1, - "name": "풋환매수량", - "offset": 15, - "start": 429 - }, - { - "fid": -1, - "name": "풋환매금액", - "offset": 15, - "start": 444 - }, - { - "fid": -1, - "name": "선물최종매도수량", - "offset": 15, - "start": 459 - }, - { - "fid": -1, - "name": "선물최종매도금액", - "offset": 15, - "start": 474 - }, - { - "fid": -1, - "name": "선물최종매도평균가격", - "offset": 9, - "start": 489 - }, - { - "fid": -1, - "name": "선물최종매수수량", - "offset": 15, - "start": 498 - }, - { - "fid": -1, - "name": "선물최종매수금액", - "offset": 15, - "start": 513 - }, - { - "fid": -1, - "name": "선물최종매수평균가격", - "offset": 9, - "start": 528 - }, - { - "fid": -1, - "name": "콜권리행사수량", - "offset": 15, - "start": 537 - }, - { - "fid": -1, - "name": "콜권리행사금액", - "offset": 15, - "start": 552 - }, - { - "fid": -1, - "name": "콜권리행사가격", - "offset": 9, - "start": 567 - }, - { - "fid": -1, - "name": "풋권리행사수량", - "offset": 15, - "start": 576 - }, - { - "fid": -1, - "name": "풋권리행사금액", - "offset": 15, - "start": 591 - }, - { - "fid": -1, - "name": "풋권리행사가격", - "offset": 9, - "start": 606 - }, - { - "fid": -1, - "name": "콜권리배정수량", - "offset": 15, - "start": 615 - }, - { - "fid": -1, - "name": "콜권리배정금액", - "offset": 15, - "start": 630 - }, - { - "fid": -1, - "name": "콜권리배정가격", - "offset": 9, - "start": 645 - }, - { - "fid": -1, - "name": "풋권리배정수량", - "offset": 15, - "start": 654 - }, - { - "fid": -1, - "name": "풋권리배정금액", - "offset": 15, - "start": 669 - }, - { - "fid": -1, - "name": "풋권리배정가격", - "offset": 9, - "start": 684 - } - ], - "single_outputs_name": "선옵당일매매변동현황", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20002", - "tr_name": "TDB3005_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20003": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "시장구분", - "offset": 1, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 11 - }, - { - "fid": -1, - "name": "시작일자", - "offset": 8, - "start": 75 - }, - { - "fid": -1, - "name": "종료일자", - "offset": 8, - "start": 83 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 91 - } - ], - "inputs_name": "선옵기간손익조회요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 1, - "start": 8 - }, - { - "fid": -1, - "name": "잔고수량", - "offset": 7, - "start": 9 - }, - { - "fid": -1, - "name": "평균가격", - "offset": 15, - "start": 16 - }, - { - "fid": -1, - "name": "전일종가", - "offset": 15, - "start": 31 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 15, - "start": 46 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 61 - } - ], - "multi_outputs_name": "선옵종목별기간손익조회", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "선물약정금액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "옵션약정금액", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "선물정산손익", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "옵션매매손익", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "총손익", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "평균예탁금액", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "수수료", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "수익율", - "offset": 9, - "start": 120 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 129 - } - ], - "single_outputs_name": "선옵기간손익조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20003", - "tr_name": "TDB3010_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20004": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "조회일", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "종목구분", - "offset": 1, - "start": 82 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 83 - }, - { - "fid": -1, - "name": "정렬구분", - "offset": 1, - "start": 84 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 85 - }, - { - "fid": -1, - "name": "정규시간외구분", - "offset": 1, - "start": 87 - } - ], - "inputs_name": "선옵주문체결내역상세요청", - "multi_outputs": [ - { - "fid": -1, - "name": "주문번호", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 10, - "start": 7 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 17 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 6, - "start": 25 - }, - { - "fid": -1, - "name": "체결수량", - "offset": 6, - "start": 31 - }, - { - "fid": -1, - "name": "미체결수량", - "offset": 6, - "start": 37 - }, - { - "fid": -1, - "name": "접수번호", - "offset": 7, - "start": 43 - }, - { - "fid": -1, - "name": "접수구분", - "offset": 1, - "start": 50 - }, - { - "fid": -1, - "name": "조작자사번", - "offset": 8, - "start": 51 - }, - { - "fid": -1, - "name": "원주문번호", - "offset": 7, - "start": 59 - }, - { - "fid": -1, - "name": "주문유형", - "offset": 1, - "start": 66 - }, - { - "fid": -1, - "name": "종목명", - "offset": 30, - "start": 67 - }, - { - "fid": -1, - "name": "주문가격", - "offset": 15, - "start": 97 - }, - { - "fid": -1, - "name": "체결가격", - "offset": 15, - "start": 112 - }, - { - "fid": -1, - "name": "체결번호", - "offset": 7, - "start": 127 - }, - { - "fid": -1, - "name": "약정시간", - "offset": 8, - "start": 134 - }, - { - "fid": -1, - "name": "접수시간", - "offset": 8, - "start": 142 - }, - { - "fid": -1, - "name": "매체", - "offset": 20, - "start": 150 - } - ], - "multi_outputs_name": "선옵주문체결내역상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20004", - "tr_name": "TDB3040_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20005": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "조회일", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "종목구분", - "offset": 1, - "start": 82 - }, - { - "fid": -1, - "name": "조회구분", - "offset": 1, - "start": 83 - }, - { - "fid": -1, - "name": "정렬구분", - "offset": 1, - "start": 84 - }, - { - "fid": -1, - "name": "정규시간외구분", - "offset": 1, - "start": 85 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 86 - } - ], - "inputs_name": "선옵주문체결내역상세평균가요청", - "multi_outputs": [ - { - "fid": -1, - "name": "주문번호", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 10, - "start": 7 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 17 - }, - { - "fid": -1, - "name": "주문수량", - "offset": 6, - "start": 25 - }, - { - "fid": -1, - "name": "체결수량", - "offset": 6, - "start": 31 - }, - { - "fid": -1, - "name": "미체결수량", - "offset": 6, - "start": 37 - }, - { - "fid": -1, - "name": "접수번호", - "offset": 7, - "start": 43 - }, - { - "fid": -1, - "name": "접수구분", - "offset": 1, - "start": 50 - }, - { - "fid": -1, - "name": "조작자사번", - "offset": 8, - "start": 51 - }, - { - "fid": -1, - "name": "원주문번호", - "offset": 7, - "start": 59 - }, - { - "fid": -1, - "name": "주문유형", - "offset": 1, - "start": 66 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 67 - }, - { - "fid": -1, - "name": "주문가격", - "offset": 15, - "start": 107 - }, - { - "fid": -1, - "name": "체결가", - "offset": 15, - "start": 122 - }, - { - "fid": -1, - "name": "체결번호", - "offset": 7, - "start": 137 - }, - { - "fid": -1, - "name": "약정시간", - "offset": 8, - "start": 144 - }, - { - "fid": -1, - "name": "접수시간", - "offset": 8, - "start": 152 - }, - { - "fid": -1, - "name": "매체", - "offset": 20, - "start": 160 - } - ], - "multi_outputs_name": "선옵주문체결내역상세평균가", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20005", - "tr_name": "TDB3040_Q02", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20006": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "조회일자", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 82 - } - ], - "inputs_name": "선옵잔고상세현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 8 - }, - { - "fid": -1, - "name": "매매일자", - "offset": 8, - "start": 48 - }, - { - "fid": -1, - "name": "매매구분", - "offset": 10, - "start": 56 - }, - { - "fid": -1, - "name": "잔고수량", - "offset": 9, - "start": 66 - }, - { - "fid": -1, - "name": "매입단가", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "매매금액", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "현재가", - "offset": 15, - "start": 115 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 15, - "start": 130 - }, - { - "fid": -1, - "name": "손익율", - "offset": 15, - "start": 145 - }, - { - "fid": -1, - "name": "평가금액", - "offset": 15, - "start": 160 - } - ], - "multi_outputs_name": "선옵잔고상세현황", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "선물매도수량", - "offset": 9, - "start": 0 - }, - { - "fid": -1, - "name": "선물매수수량", - "offset": 9, - "start": 9 - }, - { - "fid": -1, - "name": "콜매도수량", - "offset": 9, - "start": 18 - }, - { - "fid": -1, - "name": "콜매수수량", - "offset": 9, - "start": 27 - }, - { - "fid": -1, - "name": "풋매도수량", - "offset": 9, - "start": 36 - }, - { - "fid": -1, - "name": "풋매수수량", - "offset": 9, - "start": 45 - }, - { - "fid": -1, - "name": "선물매도금액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "선물매수금액", - "offset": 15, - "start": 9 - }, - { - "fid": -1, - "name": "콜매도금액", - "offset": 15, - "start": 18 - }, - { - "fid": -1, - "name": "콜매수금액", - "offset": 15, - "start": 27 - }, - { - "fid": -1, - "name": "풋매도금액", - "offset": 15, - "start": 36 - }, - { - "fid": -1, - "name": "풋매수금액", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "약정합계", - "offset": 15, - "start": 54 - }, - { - "fid": -1, - "name": "손익합계", - "offset": 15, - "start": 69 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 84 - } - ], - "single_outputs_name": "선옵잔고상세현황합계", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20006", - "tr_name": "TDB3065_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20007": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "선옵잔고현황정산가기준요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "종목명", - "offset": 20, - "start": 12 - }, - { - "fid": -1, - "name": "매도매수구분", - "offset": 1, - "start": 32 - }, - { - "fid": -1, - "name": "수량", - "offset": 12, - "start": 33 - }, - { - "fid": -1, - "name": "매입단가", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "현재가", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "평가손익", - "offset": 12, - "start": 75 - }, - { - "fid": -1, - "name": "청산가능수량", - "offset": 12, - "start": 87 - }, - { - "fid": -1, - "name": "약정금액", - "offset": 15, - "start": 99 - }, - { - "fid": -1, - "name": "평가금액", - "offset": 15, - "start": 114 - } - ], - "multi_outputs_name": "선옵잔고현황정산가기준", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "약정금액합계", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "평가손익합계", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 30 - } - ], - "single_outputs_name": "선옵잔고현황정산가기준합계", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20007", - "tr_name": "TDB3070_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20008": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "계좌별결제예상내역조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "계좌명", - "offset": 40, - "start": 0 - }, - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 40 - }, - { - "fid": -1, - "name": "추정예탁총액", - "offset": 15, - "start": 55 - }, - { - "fid": -1, - "name": "예탁현금", - "offset": 15, - "start": 70 - }, - { - "fid": -1, - "name": "추정예탁현금", - "offset": 15, - "start": 85 - }, - { - "fid": -1, - "name": "선물당일차금", - "offset": 15, - "start": 100 - }, - { - "fid": -1, - "name": "선물갱신차금", - "offset": 15, - "start": 115 - }, - { - "fid": -1, - "name": "선물최종결제차금", - "offset": 15, - "start": 130 - }, - { - "fid": -1, - "name": "선물예상정산손익", - "offset": 15, - "start": 145 - }, - { - "fid": -1, - "name": "옵션매수대금", - "offset": 15, - "start": 160 - }, - { - "fid": -1, - "name": "옵션매도대금", - "offset": 15, - "start": 175 - }, - { - "fid": -1, - "name": "옵션행사차금", - "offset": 15, - "start": 190 - }, - { - "fid": -1, - "name": "옵션배정차금", - "offset": 15, - "start": 205 - }, - { - "fid": -1, - "name": "주식옵션행사대금", - "offset": 15, - "start": 220 - }, - { - "fid": -1, - "name": "주식옵션배정대금", - "offset": 15, - "start": 235 - }, - { - "fid": -1, - "name": "인수도대금", - "offset": 15, - "start": 250 - }, - { - "fid": -1, - "name": "전일대용매도체결금액", - "offset": 15, - "start": 265 - }, - { - "fid": -1, - "name": "금일대용매도체결금액", - "offset": 15, - "start": 280 - }, - { - "fid": -1, - "name": "선물수수료", - "offset": 15, - "start": 295 - }, - { - "fid": -1, - "name": "옵션수수료", - "offset": 15, - "start": 310 - }, - { - "fid": -1, - "name": "결제가격수신여부", - "offset": 1, - "start": 325 - }, - { - "fid": -1, - "name": "유지증거금총액", - "offset": 15, - "start": 326 - }, - { - "fid": -1, - "name": "유지증거금총액부족액", - "offset": 15, - "start": 341 - }, - { - "fid": -1, - "name": "유지증거금현금부족액", - "offset": 15, - "start": 356 - }, - { - "fid": -1, - "name": "옵션잔고평가손익", - "offset": 15, - "start": 371 - }, - { - "fid": -1, - "name": "예탁대용", - "offset": 15, - "start": 386 - }, - { - "fid": -1, - "name": "익일결제예정금액", - "offset": 15, - "start": 401 - } - ], - "single_outputs_name": "계좌별결제예상내역조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20008", - "tr_name": "TDB3125_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20009": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "매도수구분", - "offset": 1, - "start": 82 - }, - { - "fid": -1, - "name": "주문유형", - "offset": 1, - "start": 83 - }, - { - "fid": -1, - "name": "주문가격", - "offset": 15, - "start": 84 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 99 - } - ], - "inputs_name": "선옵계좌별주문가능수량요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "예탁현금", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "위탁증거금", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "현금증거금", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "주문가능금액", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "주문가능총액", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "신규가능수량", - "offset": 12, - "start": 90 - }, - { - "fid": -1, - "name": "청산가능수량", - "offset": 12, - "start": 102 - }, - { - "fid": -1, - "name": "총가능수량", - "offset": 12, - "start": 114 - }, - { - "fid": -1, - "name": "주문가능총액", - "offset": 15, - "start": 126 - }, - { - "fid": -1, - "name": "필요증거금총액", - "offset": 15, - "start": 141 - }, - { - "fid": -1, - "name": "총액부족액", - "offset": 15, - "start": 156 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 15, - "start": 171 - }, - { - "fid": -1, - "name": "필요증거금현금", - "offset": 15, - "start": 186 - }, - { - "fid": -1, - "name": "현금부족액", - "offset": 15, - "start": 201 - }, - { - "fid": -1, - "name": "주문가능대용금", - "offset": 15, - "start": 216 - }, - { - "fid": -1, - "name": "필요증거금대용금", - "offset": 15, - "start": 231 - }, - { - "fid": -1, - "name": "대용금부족액", - "offset": 15, - "start": 246 - } - ], - "single_outputs_name": "선옵계좌별주문가능수량", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20009", - "tr_name": "TDB3165_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20010": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "선옵예탁금및증거금조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "예탁현금", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "에탁대용", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "증거금총액", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "증거금현금", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "증거금대용금", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "주문가능총액", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "주문가능대용금", - "offset": 15, - "start": 120 - }, - { - "fid": -1, - "name": "추가증거금총액", - "offset": 15, - "start": 135 - }, - { - "fid": -1, - "name": "추가증거금현금", - "offset": 15, - "start": 150 - }, - { - "fid": -1, - "name": "추가증거금대용금", - "offset": 15, - "start": 165 - }, - { - "fid": -1, - "name": "인출가능총액", - "offset": 15, - "start": 180 - }, - { - "fid": -1, - "name": "인출가능현금", - "offset": 15, - "start": 195 - }, - { - "fid": -1, - "name": "인출가능대용금", - "offset": 15, - "start": 210 - }, - { - "fid": -1, - "name": "순자산금액", - "offset": 15, - "start": 225 - }, - { - "fid": -1, - "name": "익일예탁총액", - "offset": 15, - "start": 240 - }, - { - "fid": -1, - "name": "개장예탁총액", - "offset": 15, - "start": 255 - }, - { - "fid": -1, - "name": "선물정산차금", - "offset": 15, - "start": 270 - }, - { - "fid": -1, - "name": "선물청산손익", - "offset": 15, - "start": 285 - }, - { - "fid": -1, - "name": "선물평가손익", - "offset": 15, - "start": 300 - }, - { - "fid": -1, - "name": "선물약정금액", - "offset": 15, - "start": 315 - }, - { - "fid": -1, - "name": "옵션결제차금", - "offset": 15, - "start": 330 - }, - { - "fid": -1, - "name": "옵션청산손익", - "offset": 15, - "start": 345 - }, - { - "fid": -1, - "name": "옵션평가손익", - "offset": 15, - "start": 360 - }, - { - "fid": -1, - "name": "옵션약정금액", - "offset": 15, - "start": 375 - }, - { - "fid": -1, - "name": "전일장종료예탁총액", - "offset": 15, - "start": 390 - }, - { - "fid": -1, - "name": "전일장종료예탁현금", - "offset": 15, - "start": 405 - }, - { - "fid": -1, - "name": "전일장종료예탁대용금", - "offset": 15, - "start": 420 - } - ], - "single_outputs_name": "선옵예탁금및증거금조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20010", - "tr_name": "TDB3190_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20011": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "증거금구분", - "offset": 1, - "start": 74 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 75 - } - ], - "inputs_name": "선옵계좌예비증거금상세요청", - "multi_outputs": [ - { - "fid": -1, - "name": "기초자산명", - "offset": 20, - "start": 0 - }, - { - "fid": -1, - "name": "최대구간증거금", - "offset": 12, - "start": 20 - }, - { - "fid": -1, - "name": "증거금감면액", - "offset": 12, - "start": 32 - }, - { - "fid": -1, - "name": "구간증거금01", - "offset": 12, - "start": 44 - }, - { - "fid": -1, - "name": "구간증거금02", - "offset": 12, - "start": 56 - }, - { - "fid": -1, - "name": "구간증거금03", - "offset": 12, - "start": 68 - }, - { - "fid": -1, - "name": "구간증거금04", - "offset": 12, - "start": 80 - }, - { - "fid": -1, - "name": "구간증거금05", - "offset": 12, - "start": 92 - }, - { - "fid": -1, - "name": "구간증거금06", - "offset": 12, - "start": 104 - }, - { - "fid": -1, - "name": "구간증거금07", - "offset": 12, - "start": 116 - }, - { - "fid": -1, - "name": "구간증거금08", - "offset": 12, - "start": 128 - }, - { - "fid": -1, - "name": "구간증거금09", - "offset": 12, - "start": 140 - }, - { - "fid": -1, - "name": "구간증거금10", - "offset": 12, - "start": 152 - }, - { - "fid": -1, - "name": "구간증거금11", - "offset": 12, - "start": 164 - }, - { - "fid": -1, - "name": "구간증거금12", - "offset": 12, - "start": 176 - }, - { - "fid": -1, - "name": "구간증거금13", - "offset": 12, - "start": 188 - }, - { - "fid": -1, - "name": "구간증거금14", - "offset": 12, - "start": 200 - }, - { - "fid": -1, - "name": "구간증거금15", - "offset": 12, - "start": 212 - }, - { - "fid": -1, - "name": "구간증거금16", - "offset": 12, - "start": 224 - }, - { - "fid": -1, - "name": "구간증거금17", - "offset": 12, - "start": 236 - }, - { - "fid": -1, - "name": "구간증거금18", - "offset": 12, - "start": 248 - }, - { - "fid": -1, - "name": "구간증거금19", - "offset": 12, - "start": 260 - }, - { - "fid": -1, - "name": "구간증거금20", - "offset": 12, - "start": 272 - }, - { - "fid": -1, - "name": "구간증거금21", - "offset": 12, - "start": 284 - }, - { - "fid": -1, - "name": "구간증거금22", - "offset": 12, - "start": 296 - }, - { - "fid": -1, - "name": "구간증거금23", - "offset": 12, - "start": 308 - }, - { - "fid": -1, - "name": "구간증거금24", - "offset": 12, - "start": 320 - }, - { - "fid": -1, - "name": "구간증거금25", - "offset": 12, - "start": 332 - }, - { - "fid": -1, - "name": "구간증거금26", - "offset": 12, - "start": 344 - }, - { - "fid": -1, - "name": "구간증거금27", - "offset": 12, - "start": 356 - }, - { - "fid": -1, - "name": "구간증거금28", - "offset": 12, - "start": 368 - }, - { - "fid": -1, - "name": "구간증거금29", - "offset": 12, - "start": 380 - }, - { - "fid": -1, - "name": "구간증거금30", - "offset": 12, - "start": 392 - }, - { - "fid": -1, - "name": "구간증거금31", - "offset": 12, - "start": 404 - }, - { - "fid": -1, - "name": "구간증거금32", - "offset": 12, - "start": 416 - }, - { - "fid": -1, - "name": "구간증거금33", - "offset": 12, - "start": 428 - }, - { - "fid": -1, - "name": "구간증거금34", - "offset": 12, - "start": 440 - }, - { - "fid": -1, - "name": "구간증거금35", - "offset": 12, - "start": 452 - }, - { - "fid": -1, - "name": "구간증거금36", - "offset": 12, - "start": 464 - }, - { - "fid": -1, - "name": "구간증거금37", - "offset": 12, - "start": 476 - }, - { - "fid": -1, - "name": "구간증거금38", - "offset": 12, - "start": 488 - }, - { - "fid": -1, - "name": "구간증거금39", - "offset": 12, - "start": 500 - }, - { - "fid": -1, - "name": "구간증거금40", - "offset": 12, - "start": 512 - }, - { - "fid": -1, - "name": "구간증거금41", - "offset": 12, - "start": 524 - }, - { - "fid": -1, - "name": "구간증거금42", - "offset": 12, - "start": 536 - }, - { - "fid": -1, - "name": "구간증거금43", - "offset": 12, - "start": 548 - }, - { - "fid": -1, - "name": "구간증거금44", - "offset": 12, - "start": 560 - }, - { - "fid": -1, - "name": "구간증거금45", - "offset": 12, - "start": 572 - }, - { - "fid": -1, - "name": "구간증거금46", - "offset": 12, - "start": 584 - }, - { - "fid": -1, - "name": "구간증거금47", - "offset": 12, - "start": 596 - }, - { - "fid": -1, - "name": "구간증거금48", - "offset": 12, - "start": 608 - }, - { - "fid": -1, - "name": "구간증거금49", - "offset": 12, - "start": 620 - }, - { - "fid": -1, - "name": "구간증거금50", - "offset": 12, - "start": 632 - }, - { - "fid": -1, - "name": "구간증거금51", - "offset": 12, - "start": 644 - }, - { - "fid": -1, - "name": "구간증거금52", - "offset": 12, - "start": 656 - }, - { - "fid": -1, - "name": "구간증거금53", - "offset": 12, - "start": 668 - }, - { - "fid": -1, - "name": "구간증거금54", - "offset": 12, - "start": 680 - }, - { - "fid": -1, - "name": "구간증거금55", - "offset": 12, - "start": 692 - }, - { - "fid": -1, - "name": "구간증거금56", - "offset": 12, - "start": 704 - }, - { - "fid": -1, - "name": "구간증거금57", - "offset": 12, - "start": 716 - }, - { - "fid": -1, - "name": "구간증거금58", - "offset": 12, - "start": 728 - }, - { - "fid": -1, - "name": "구간증거금59", - "offset": 12, - "start": 740 - }, - { - "fid": -1, - "name": "구간증거금60", - "offset": 12, - "start": 752 - }, - { - "fid": -1, - "name": "구간증거금61", - "offset": 12, - "start": 764 - }, - { - "fid": -1, - "name": "구간증거금62", - "offset": 12, - "start": 776 - } - ], - "multi_outputs_name": "선옵계좌예비증거금상세", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 0 - } - ], - "single_outputs_name": "출력건수", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20011", - "tr_name": "TDB3195_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20012": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 74 - } - ], - "inputs_name": "선옵증거금상세내역요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 0 - }, - { - "fid": -1, - "name": "예탁현금", - "offset": 15, - "start": 15 - }, - { - "fid": -1, - "name": "예탁대용", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "위탁증거금총액", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "위탁현금증거금", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "유지증거금총액", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "추가증거금총액", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "추가증거금현금", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "신규위탁증거금총액", - "offset": 15, - "start": 120 - }, - { - "fid": -1, - "name": "선물신규주문증거금총액", - "offset": 15, - "start": 135 - }, - { - "fid": -1, - "name": "신규스프레드증거금", - "offset": 15, - "start": 150 - }, - { - "fid": -1, - "name": "옵션신규매수주문", - "offset": 15, - "start": 165 - }, - { - "fid": -1, - "name": "옵션신규매도주문", - "offset": 15, - "start": 180 - }, - { - "fid": -1, - "name": "위험위탁증거금", - "offset": 15, - "start": 195 - }, - { - "fid": -1, - "name": "옵션가격증거금", - "offset": 15, - "start": 210 - }, - { - "fid": -1, - "name": "가격변동증거금", - "offset": 15, - "start": 225 - }, - { - "fid": -1, - "name": "선물스프레드증거금", - "offset": 15, - "start": 240 - }, - { - "fid": -1, - "name": "인수도증거금", - "offset": 15, - "start": 255 - }, - { - "fid": -1, - "name": "최소증거금", - "offset": 15, - "start": 270 - }, - { - "fid": -1, - "name": "당일옵션순매수대금", - "offset": 15, - "start": 285 - }, - { - "fid": -1, - "name": "옵션매수대금", - "offset": 15, - "start": 300 - }, - { - "fid": -1, - "name": "선물체결순손익", - "offset": 15, - "start": 315 - }, - { - "fid": -1, - "name": "선물정산차금", - "offset": 15, - "start": 330 - }, - { - "fid": -1, - "name": "옵션매도결제대금", - "offset": 15, - "start": 345 - }, - { - "fid": -1, - "name": "옵션매수결제대금", - "offset": 15, - "start": 360 - }, - { - "fid": -1, - "name": "수수료합계", - "offset": 15, - "start": 375 - }, - { - "fid": -1, - "name": "선물최종결제차금", - "offset": 15, - "start": 390 - }, - { - "fid": -1, - "name": "인수도대금", - "offset": 15, - "start": 405 - }, - { - "fid": -1, - "name": "옵션행사대금", - "offset": 15, - "start": 420 - }, - { - "fid": -1, - "name": "옵션배정대금", - "offset": 15, - "start": 435 - }, - { - "fid": -1, - "name": "주문가능총액", - "offset": 15, - "start": 450 - }, - { - "fid": -1, - "name": "주문가능현금", - "offset": 15, - "start": 465 - }, - { - "fid": -1, - "name": "인출가능총액", - "offset": 15, - "start": 480 - }, - { - "fid": -1, - "name": "인출가능현금", - "offset": 15, - "start": 495 - }, - { - "fid": -1, - "name": "계좌명", - "offset": 20, - "start": 510 - }, - { - "fid": -1, - "name": "계좌번호", - "offset": 40, - "start": 530 - }, - { - "fid": -1, - "name": "조회일자", - "offset": 12, - "start": 570 - }, - { - "fid": -1, - "name": "예탁평가총액", - "offset": 15, - "start": 582 - }, - { - "fid": -1, - "name": "익일예탁총액", - "offset": 15, - "start": 597 - }, - { - "fid": -1, - "name": "전일대용매도금", - "offset": 15, - "start": 612 - }, - { - "fid": -1, - "name": "금일대용매도금액", - "offset": 15, - "start": 627 - }, - { - "fid": -1, - "name": "미수연체료", - "offset": 15, - "start": 642 - }, - { - "fid": -1, - "name": "전일장종료예탁총액", - "offset": 15, - "start": 657 - }, - { - "fid": -1, - "name": "전일장종료예탁현금", - "offset": 15, - "start": 672 - }, - { - "fid": -1, - "name": "장중인출가능금액변경여부", - "offset": 1, - "start": 687 - } - ], - "single_outputs_name": "선옵증거금상세내역", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20012", - "tr_name": "TDB3205_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20013": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 74 - }, - { - "fid": -1, - "name": "주문가격", - "offset": 15, - "start": 82 - } - ], - "inputs_name": "계좌미결제청산가능수량조회요청", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "미결제수량", - "offset": 7, - "start": 0 - }, - { - "fid": -1, - "name": "청산가능수량", - "offset": 7, - "start": 7 - }, - { - "fid": -1, - "name": "현재증거금총액", - "offset": 15, - "start": 14 - }, - { - "fid": -1, - "name": "현재증거금현금", - "offset": 15, - "start": 29 - }, - { - "fid": -1, - "name": "예상위탁증거금", - "offset": 15, - "start": 44 - }, - { - "fid": -1, - "name": "예상현금증거금", - "offset": 15, - "start": 59 - } - ], - "single_outputs_name": "계좌미결제청산가능수량조회", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20013", - "tr_name": "TDB3210_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20014": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "계좌번호", - "offset": 10, - "start": 0 - }, - { - "fid": -1, - "name": "비밀번호", - "offset": 64, - "start": 10 - }, - { - "fid": -1, - "name": "KOSPI200지수", - "offset": 7, - "start": 74 - }, - { - "fid": -1, - "name": "비밀번호입력매체구분", - "offset": 2, - "start": 81 - } - ], - "inputs_name": "선옵실시간증거금산출요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 8, - "start": 0 - }, - { - "fid": -1, - "name": "매도매수구분", - "offset": 1, - "start": 8 - }, - { - "fid": -1, - "name": "미결제수량", - "offset": 7, - "start": 9 - }, - { - "fid": -1, - "name": "현재가", - "offset": 15, - "start": 16 - }, - { - "fid": -1, - "name": "내재변동성", - "offset": 10, - "start": 31 - }, - { - "fid": -1, - "name": "이론지수", - "offset": 15, - "start": 41 - }, - { - "fid": -1, - "name": "잔존일수", - "offset": 3, - "start": 56 - } - ], - "multi_outputs_name": "선옵내재변동성", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "계좌명", - "offset": 30, - "start": 0 - }, - { - "fid": -1, - "name": "예탁총액", - "offset": 15, - "start": 30 - }, - { - "fid": -1, - "name": "예탁현금", - "offset": 15, - "start": 45 - }, - { - "fid": -1, - "name": "예탁대용금", - "offset": 15, - "start": 60 - }, - { - "fid": -1, - "name": "위탁증거금", - "offset": 15, - "start": 75 - }, - { - "fid": -1, - "name": "현금증거금", - "offset": 15, - "start": 90 - }, - { - "fid": -1, - "name": "추가증거금총액", - "offset": 15, - "start": 105 - }, - { - "fid": -1, - "name": "추가증거금현금", - "offset": 15, - "start": 120 - }, - { - "fid": -1, - "name": "추정예탁총액", - "offset": 15, - "start": 135 - }, - { - "fid": -1, - "name": "추정예탁현금", - "offset": 15, - "start": 150 - }, - { - "fid": -1, - "name": "추정위탁증거금총액", - "offset": 15, - "start": 165 - }, - { - "fid": -1, - "name": "추정위탁증거금현금", - "offset": 15, - "start": 180 - }, - { - "fid": -1, - "name": "추정유지증거금총액", - "offset": 15, - "start": 195 - }, - { - "fid": -1, - "name": "추정유지증거금현금", - "offset": 15, - "start": 210 - }, - { - "fid": -1, - "name": "추정추가증거금총액", - "offset": 15, - "start": 225 - }, - { - "fid": -1, - "name": "추정추가증거금현금", - "offset": 15, - "start": 240 - }, - { - "fid": -1, - "name": "선물당일차금", - "offset": 15, - "start": 255 - }, - { - "fid": -1, - "name": "옵션결제대금", - "offset": 15, - "start": 270 - }, - { - "fid": -1, - "name": "인수도대금", - "offset": 15, - "start": 285 - }, - { - "fid": -1, - "name": "수수료", - "offset": 15, - "start": 300 - }, - { - "fid": -1, - "name": "선물갱신차금", - "offset": 15, - "start": 315 - }, - { - "fid": -1, - "name": "선물최종차금", - "offset": 15, - "start": 330 - }, - { - "fid": -1, - "name": "옵션행사배정대금", - "offset": 15, - "start": 345 - }, - { - "fid": -1, - "name": "유지증거금기준부족액", - "offset": 15, - "start": 360 - }, - { - "fid": -1, - "name": "위탁증거금기준부족액", - "offset": 15, - "start": 375 - }, - { - "fid": -1, - "name": "사후증거금계좌구분", - "offset": 1, - "start": 390 - }, - { - "fid": -1, - "name": "결제가격수신여부", - "offset": 1, - "start": 391 - }, - { - "fid": -1, - "name": "장종료예탁총액", - "offset": 15, - "start": 392 - }, - { - "fid": -1, - "name": "장종료예탁현금", - "offset": 15, - "start": 407 - }, - { - "fid": -1, - "name": "장종료예탁대용금", - "offset": 15, - "start": 422 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 437 - } - ], - "single_outputs_name": "선옵실시간증거금산출", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20014", - "tr_name": "TDB3215_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20015": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "월물구분", - "offset": 6, - "start": 0 - }, - { - "fid": -1, - "name": "클래스구분", - "offset": 2, - "start": 1 - } - ], - "inputs_name": "옵션매도주문증거금현황요청", - "multi_outputs": [ - { - "fid": -1, - "name": "콜조정이론가", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "콜최대이론가", - "offset": 12, - "start": 12 - }, - { - "fid": -1, - "name": "콜전일종가", - "offset": 12, - "start": 24 - }, - { - "fid": -1, - "name": "콜주문증거금", - "offset": 15, - "start": 36 - }, - { - "fid": -1, - "name": "행사가격", - "offset": 12, - "start": 51 - }, - { - "fid": -1, - "name": "풋주문증거금", - "offset": 15, - "start": 63 - }, - { - "fid": -1, - "name": "풋전일종가", - "offset": 12, - "start": 78 - }, - { - "fid": -1, - "name": "풋최대이론가", - "offset": 12, - "start": 90 - }, - { - "fid": -1, - "name": "풋조정이론가", - "offset": 12, - "start": 102 - } - ], - "multi_outputs_name": "옵션매도주문증거금", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "조회건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "ATM행사가격", - "offset": 12, - "start": 12 - }, - { - "fid": -1, - "name": "위치", - "offset": 4, - "start": 24 - }, - { - "fid": -1, - "name": "조회건수", - "offset": 4, - "start": 28 - } - ], - "single_outputs_name": "옵션행사가", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20015", - "tr_name": "TDB3220_Q01", - "tr_name_svr": "WINGSF", - "tr_type": "2" - }, - "opw20016": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "신용종목등급구분", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "시장거래구분", - "offset": 1, - "start": 1 - }, - { - "fid": -1, - "name": "종목번호", - "offset": 12, - "start": 2 - } - ], - "inputs_name": "신용융자 가능종목요청", - "multi_outputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "종목명", - "offset": 40, - "start": 0 - }, - { - "fid": -1, - "name": "신용보즘금율", - "offset": 4, - "start": 0 - }, - { - "fid": -1, - "name": "대용가", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "전일종가", - "offset": 12, - "start": 0 - }, - { - "fid": -1, - "name": "신용한도초과여부", - "offset": 1, - "start": 0 - }, - { - "fid": -1, - "name": "신용한도초과", - "offset": 40, - "start": 0 - } - ], - "multi_outputs_name": "신용융자가능종목", - "multi_outputs_params": { - "four_if_multi": "4", - "max_repeat_count": "*", - "repeat_count_desc": "출력건수" - }, - "single_outputs": [ - { - "fid": -1, - "name": "신용융자가능여부", - "offset": 40, - "start": 0 - }, - { - "fid": -1, - "name": "출력건수", - "offset": 4, - "start": 30 - } - ], - "single_outputs_name": "신용융자가능여부", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20016", - "tr_name": "TTA4016_Q01", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - }, - "opw20017": { - "gfid": "", - "inputs": [ - { - "fid": -1, - "name": "종목코드", - "offset": 12, - "start": 0 - } - ], - "inputs_name": "신용융자 가능문의", - "multi_outputs": [], - "multi_outputs_name": "", - "multi_outputs_params": { - "four_if_multi": null, - "max_repeat_count": null, - "repeat_count_desc": null - }, - "single_outputs": [ - { - "fid": -1, - "name": "신용가능여부", - "offset": 40, - "start": 0 - } - ], - "single_outputs_name": "신용융자가능여부", - "single_outputs_params": { - "four_if_multi": "*", - "max_repeat_count": "*", - "repeat_count_desc": "*" - }, - "tr_code": "opw20017", - "tr_name": "TTA4016_Q02", - "tr_name_svr": "WINGSJ", - "tr_type": "2" - } -} \ No newline at end of file diff --git a/koapy/backend/kiwoom_open_api_plus/data/scripts/install.iss b/koapy/backend/kiwoom_open_api_plus/data/scripts/install.iss deleted file mode 100644 index aa426742..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/scripts/install.iss +++ /dev/null @@ -1,27 +0,0 @@ -[InstallShield Silent] -Version=v7.00 -File=Response File -[File Transfer] -OverwrittenReadOnly=NoToAll -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-DlgOrder] -Dlg0={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdWelcome-0 -Count=4 -Dlg1={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdAskDestPath2-0 -Dlg2={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdStartCopy2-0 -Dlg3={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdFinish-0 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdWelcome-0] -Result=1 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdAskDestPath2-0] -szDir=C:\ -Result=1 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdStartCopy2-0] -Result=1 -[Application] -Name=OpenAPI -Version=1.00.0000 -Company=Ű¿òÁõ±Ç -Lang=0412 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdFinish-0] -Result=1 -bOpt1=0 -bOpt2=0 diff --git a/koapy/backend/kiwoom_open_api_plus/data/scripts/setup.ps1 b/koapy/backend/kiwoom_open_api_plus/data/scripts/setup.ps1 deleted file mode 100644 index 3736ba98..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/scripts/setup.ps1 +++ /dev/null @@ -1,66 +0,0 @@ -Function New-TemporaryDirectory { - $Parent = [System.IO.Path]::GetTempPath() - [string] $Name = [System.Guid]::NewGuid() - New-Item -ItemType Directory -Path (Join-Path "$Parent" "$Name") -} - -Function Invoke-DownloadFile { - Param ( - $Address, - $FilePath - ) - (New-Object System.Net.WebClient).DownloadFile("$Address", "$FilePath") -} - -Function Get-OpenAPISetupFile { - Param ( - $FilePath - ) - $SetupFile = "OpenAPISetup.exe" - $SetupFileURL = "https://download.kiwoom.com/web/openapi/$SetupFile" - Invoke-DownloadFile -Address "$SetupFileURL" -FilePath "$FilePath" -} - -Function Start-OpenAPISetupProcess { - Param ( - $ISSFilePath - ) - Write-Output "Creating Temporary Directory" - $TempDir = New-TemporaryDirectory - Write-Output "Created Temporary Directory: $TempDir" - Try { - $SetupFile = "OpenAPISetup.exe" - $SetupFilePath = "$TempDir\$SetupFile" - Write-Output "Downloading Installer" - Get-OpenAPISetupFile -FilePath "$SetupFilePath" - Write-Output "Downloaded Installer Location: $SetupFilePath" - If ($ISSFilePath.EndsWith("\install.iss")) { - Write-Output "Installing OpenAPI" - } - ElseIf ($ISSFilePath.EndsWith("\uninstall.iss")) { - Write-Output "Uninstalling OpenAPI" - } - Write-Output "Starting Installer Process with ISSFile: $ISSFilePath" - Start-Process -WorkingDirectory "$TempDir" -FilePath "$SetupFilePath" -ArgumentList "/s /f1`"$ISSFilePath`"" -Wait - Write-Output "Installer Process Finished" - If ($ISSFilePath.EndsWith("\install.iss")) { - Write-Output "Installed OpenAPI" - } - ElseIf ($ISSFilePath.EndsWith("\uninstall.iss")) { - Write-Output "Uninstalled OpenAPI" - } - } - Finally { - Remove-Item "$TempDir" -Recurse -ErrorAction Ignore - } -} - -Function Install-OpenAPI { - Start-OpenAPISetupProcess -ISSFilePath "$PSScriptRoot\install.iss" -} - -Function Uninstall-OpenAPI { - Start-OpenAPISetupProcess -ISSFilePath "$PSScriptRoot\uninstall.iss" -} - -Install-OpenAPI diff --git a/koapy/backend/kiwoom_open_api_plus/data/scripts/uninstall.iss b/koapy/backend/kiwoom_open_api_plus/data/scripts/uninstall.iss deleted file mode 100644 index a736b817..00000000 --- a/koapy/backend/kiwoom_open_api_plus/data/scripts/uninstall.iss +++ /dev/null @@ -1,22 +0,0 @@ -[InstallShield Silent] -Version=v7.00 -File=Response File -[File Transfer] -OverwrittenReadOnly=NoToAll -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-DlgOrder] -Dlg0={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdWelcomeMaint-0 -Count=3 -Dlg1={2511BD09-8645-4E34-9E21-563C82DB30C0}-MessageBox-0 -Dlg2={2511BD09-8645-4E34-9E21-563C82DB30C0}-SdFinishReboot-0 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdWelcomeMaint-0] -Result=303 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-MessageBox-0] -Result=6 -[Application] -Name=OpenAPI -Version=1.00.0000 -Company=Ű¿òÁõ±Ç -Lang=0412 -[{2511BD09-8645-4E34-9E21-563C82DB30C0}-SdFinishReboot-0] -Result=1 -BootOption=0 diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto deleted file mode 100644 index 46a56362..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto +++ /dev/null @@ -1,310 +0,0 @@ -syntax = "proto3"; - -package koapy.backend.kiwoom_open_api_plus.grpc; - -service KiwoomOpenApiPlusService { - - // 1. rpcs for general function calls - - rpc Call (CallRequest) returns (CallResponse) { - // unary rpc for an arbitrary function call, - // can invoke arbitrary function on the server side by giving its name and arguments, - // currently only simple data types like str and int are supported for arguments and return values - }; - - // 2. rpcs for listening and handling events - - rpc Listen (ListenRequest) returns (stream ListenResponse) { - // server streaming rpc usually for listening events, - // server will simply send stream items to client whenever event that is being listened is triggered, - // client can handle those events solely on its own on client side but there is no guarantee that it will be synced with the server, - // which means that event handler on the server side will not wait for the client to finish handling each event - }; - rpc BidirectionalListen (stream BidirectionalListenRequest) returns (stream ListenResponse) { - // bidirectional streaming rpc usually for listening and handling events with proper callbacks, - // server will send an stream item to client whenever an event is triggered and will wait for an client's ack, - // so that following callbacks from the client can actually be processed inside the server's event handler context - }; - - // 3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns - - rpc LoginCall (LoginRequest) returns (stream ListenResponse) { - // server streaming rpc for login/connect scenario, - // would invoke CommConnect() and wait for OnEventConnect() event to test its success - }; - rpc TransactionCall (TransactionRequest) returns (stream ListenResponse) { - // server streaming rpc for general transaction requests, - // would invoke CommRqData() with several SetInputValue()s for a transaction request, - // would wait for OnReceiveTrData() events, - // would handle those events to gather results by invoking GetRepeatCnt() and GetCommData() inside, - // might do additional CommRqData() and SetInputValue() inside event handler for possible consecutive lookups - }; - rpc OrderCall (OrderRequest) returns (stream ListenResponse) { - // server streaming rpc for making orders (buy/sell + update/cancel), - // would invoke SendOrder() for submitting an order, - // would wait for OnReceiveTrData() and OnReceiveChejanData() events to track its progress - }; - rpc RealCall (RealRequest) returns (stream ListenResponse) { - // server streaming rpc for listening realtime data events, - // certain transaction requests would also register some realtime data to be sent, - // but usually would just call SetRealReg() to register desired realtime data to listen explicitly, - // and would call SetRealRemove() to unregister them after done using, - // would wait for OnReceiveRealData() events - }; - rpc LoadConditionCall (LoadConditionRequest) returns (stream ListenResponse) { - // server streaming rpc for loading condition settings for conditioned search, - // would call GetConditionLoad() and wait for OnReceiveConditionVer() event to test its success - }; - rpc ConditionCall (ConditionRequest) returns (stream ListenResponse) { - // server streaming rpc for conditioned search (serching stocks with serveral conditions), - // would call SendCondition() and wait for OnReceiveTrCondition() or OnReceiveRealCondition() based on its requested type - }; - - // 4. rpcs for more complex use cases based on the previously categorized simple cases above - - rpc BidirectionalRealCall(stream BidirectionalRealRequest) returns (stream ListenResponse) { - // bidirectional streaming rpc for listening realtime data events, - // with capability of managing observation pool (what stocks, what fields to listen to) online, - // those management requests would be sent over the client streaming line, - // and ordinary realtime data events would be sent over the server streaming line - }; - rpc OrderListen (ListenRequest) returns (stream ListenResponse) { - // server streaming rpc for just listening order events (without submiting any order request compared to the simple case), - // this is one-sided streaming rpc (server streaming rpc) like Listen() rpc, - // so server would just send stream items with no consideration on coordination with its client - }; - - // 5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) - - rpc CustomListen (ListenRequest) returns (stream ListenResponse) { - // pretty much similar to server streaming Listen() rpc, - // but event handler would be instantiated dynamically based on the code given through the request - }; - rpc CustomCallAndListen (CallAndListenRequest) returns (stream CallAndListenResponse) { - // pretty much similar to server streaming XXXCall() rpcs (or even Call() rpc), - // but event handler would be instantiated dynamically based on the code given through the request - }; - - // 6. rpcs for other mics scenarios - - rpc SetLogLevel (SetLogLevelRequest) returns (SetLogLevelResponse) { - // would update log level of process that this grpc server lives - }; - -} - - -message Argument { - oneof value { - string string_value = 1; - int64 long_value = 2; - bool bool_value = 3; - } -} - -message CallRequest { - string name = 1; - repeated Argument arguments = 2; -} - -message ReturnValue { - oneof value { - string string_value = 1; - int64 long_value = 2; - bool bool_value = 3; - } -} - -message CallResponse { - ReturnValue return_value = 1; -} - - -message ListenRequest { - string id = 1; - repeated string slots = 2; - string code = 3; - string class_name = 4; -} - - -message HandledRequest { - float time = 1; -} - -message StopListenRequest { - float time = 1; -} - -message BidirectionalListenRequest { - oneof request { - ListenRequest listen_request = 1; - HandledRequest handled_request = 2; - StopListenRequest stop_listen_request = 3; - } -} - - -message SingleData { - repeated string names = 1; - repeated string values = 2; -} - -message RepeatedString { - repeated string values = 1; -} - -message MultiData { - repeated string names = 1; - repeated RepeatedString values = 2; -} - - -message ListenResponse { - string name = 1; - repeated Argument arguments = 2; - SingleData single_data = 3; - MultiData multi_data = 4; -} - - -message CallAndListenRequest { - CallRequest call_request = 1; - ListenRequest listen_request = 2; -} - -message CallAndListenResponse { - oneof response { - CallResponse call_response = 1; - ListenResponse listen_response = 2; - } -} - - -message LoginCredentials { - string user_id = 1; - string user_password = 2; - string cert_password = 3; - bool is_simulation = 4; - map account_passwords = 5; -} - -message LoginRequest { - LoginCredentials credentials = 1; -} - - -message RealRequestFlags { - bool infer_fids = 1; - bool readable_names = 2; - bool fast_parse = 3; -} - -message RealRequest { - repeated string screen_no = 1; - repeated string code_list = 2; - repeated int32 fid_list = 3; - string opt_type = 4; - RealRequestFlags flags = 5; -} - - -enum TransactionStopConditionCompartor { - LESS_THAN_OR_EQUAL_TO = 0; - LESS_THAN = 1; - GREATER_THAN_OR_EQUAL_TO = 2; - GREATER_THAN = 3; - EQUAL_TO = 4; - NOT_EQUAL_TO = 5; -} - -message TransactionStopCondition { - string name = 1; - string value = 2; - TransactionStopConditionCompartor comparator = 3; -} - -message TransactionRequest { - string request_name = 1; - string transaction_code = 2; - string screen_no = 3; - map inputs = 4; - TransactionStopCondition stop_condition = 5; - RealRequestFlags flags = 6; -} - - -message OrderSubscriptionTarget { - bool RET = 1; - bool TR = 2; - bool REAL = 3; - bool MSG = 4; - bool CHEJAN = 5; -} - -message OrderRequest { - string request_name = 1; - string screen_no = 2; - string account_no = 3; - int64 order_type = 4; - string code = 5; - int64 quantity = 6; - int64 price = 7; - string quote_type = 8; - string original_order_no = 9; - OrderSubscriptionTarget target = 10; -} - - -message LoadConditionRequest { -} - -message ConditionRequestFlags { - bool with_info = 1; - bool is_future_option = 2; -} - -message ConditionRequest { - string screen_no = 1; - string condition_name = 2; - int32 condition_index = 3; - int32 search_type = 4; - string request_name = 5; - ConditionRequestFlags flags = 6; -} - - -message SetLogLevelRequest { - int32 level = 1; - string logger = 2; -} - -message SetLogLevelResponse { -} - - -message BidirectionalRealInitializeRequest { - repeated int32 fid_list = 1; - RealRequestFlags flags = 2; -} - -message BidirectionalRealRegisterRequest { - repeated string code_list = 1; - repeated int32 fid_list = 2; -} - -message BidirectionalRealRemoveRequest { - repeated string code_list = 1; -} - -message BidirectionalRealStopRequest { -} - -message BidirectionalRealRequest { - oneof request { - BidirectionalRealInitializeRequest initialize_request = 1; - BidirectionalRealRegisterRequest register_request = 2; - BidirectionalRealRemoveRequest remove_request = 3; - BidirectionalRealStopRequest stop_request = 4; - } -} diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.py deleted file mode 100644 index 44a7e488..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient.py +++ /dev/null @@ -1,130 +0,0 @@ -import inspect - -from concurrent.futures import ThreadPoolExecutor - -import grpc - -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2_grpc -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper import ( - KiwoomOpenApiPlusServiceClientStubWrapper, -) -from koapy.config import config - - -class KiwoomOpenApiPlusServiceClient: - def __init__( - self, - host=None, - port=None, - credentials=None, - thread_pool=None, - check_timeout=None, - **kwargs, - ): - if host is None: - host = config.get_string( - "koapy.backend.kiwoom_open_api_plus.grpc.host", "localhost" - ) - host = config.get_string( - "koapy.backend.kiwoom_open_api_plus.grpc.client.host", host - ) - if port is None: - port = config.get_int("koapy.backend.kiwoom_open_api_plus.grpc.port") - port = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.client.port", port - ) - - if check_timeout is None: - check_timeout = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.client.is_ready.timeout", 10 - ) - - self._host = host - self._port = port - self._credentials = credentials - self._thread_pool = thread_pool - self._check_timeout = check_timeout - self._kwargs = kwargs - - self._target = self._host + ":" + str(self._port) - - if self._credentials is None: - channel_signature = inspect.signature(grpc.insecure_channel) - channel_params = list(channel_signature.parameters.keys()) - channel_kwargs = { - k: v for k, v in self._kwargs.items() if k in channel_params - } - channel_bound_arguments = channel_signature.bind_partial(**channel_kwargs) - channel_bound_arguments.arguments["target"] = self._target - self._channel = grpc.insecure_channel( - *channel_bound_arguments.args, - **channel_bound_arguments.kwargs, - ) - else: - channel_signature = inspect.signature(grpc.secure_channel) - channel_params = list(channel_signature.parameters.keys()) - channel_kwargs = { - k: v for k, v in self._kwargs.items() if k in channel_params - } - channel_bound_arguments = channel_signature.bind_partial(**channel_kwargs) - channel_bound_arguments.arguments["target"] = self._target - channel_bound_arguments.arguments["credentials"] = self._credentials - self._channel = grpc.secure_channel( - *channel_bound_arguments.args, - **channel_bound_arguments.kwargs, - ) - - if self._thread_pool is None: - thread_pool_signature = inspect.signature(ThreadPoolExecutor) - thread_pool_params = list(thread_pool_signature.parameters.keys()) - thread_pool_kwargs = { - k: v for k, v in self._kwargs.items() if k in thread_pool_params - } - thread_pool_bound_arguments = thread_pool_signature.bind( - **thread_pool_kwargs - ) - if thread_pool_bound_arguments.arguments.get("max_workers") is None: - max_workers = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.client.max_workers", - 8, - ) - thread_pool_bound_arguments.arguments["max_workers"] = max_workers - self._thread_pool = ThreadPoolExecutor( - *thread_pool_bound_arguments.args, - **thread_pool_bound_arguments.kwargs, - ) - - self._stub = KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceStub( - self._channel - ) - self._stub_wrapped = KiwoomOpenApiPlusServiceClientStubWrapper( - self._stub, self._thread_pool - ) - - def is_ready(self, timeout=None): - if timeout is None: - timeout = self._check_timeout - try: - grpc.channel_ready_future(self._channel).result(timeout=timeout) - return True - except grpc.FutureTimeoutError: - return False - - def get_grpc_stub(self): - return self._stub - - def get_stub(self): - return self._stub_wrapped - - def close(self): - return self._channel.close() - - def __getattr__(self, name): - return getattr(self._stub_wrapped, name) - - def __enter__(self): - assert self.is_ready(), "Client is not ready" - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.close() diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.py deleted file mode 100644 index 90898798..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable.py +++ /dev/null @@ -1,34 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import ( - convert_arguments_from_python_to_protobuf, -) - - -class KiwoomOpenApiPlusServiceClientSideDynamicCallable: - def __init__(self, stub, name): - self._stub = stub - self._name = name - - @classmethod - def _create_call_request(cls, name, args): - request = KiwoomOpenApiPlusService_pb2.CallRequest() - request.name = name - convert_arguments_from_python_to_protobuf(args, request.arguments) - return request - - @classmethod - def _unpack_response(cls, response): - if response.return_value.HasField("string_value"): - return response.return_value.string_value - elif response.return_value.HasField("bool_value"): - return response.return_value.bool_value - elif response.return_value.HasField("long_value"): - return response.return_value.long_value - else: - return None - - def __call__(self, *args): - request = self._create_call_request(self._name, args) - response = self._stub.Call(request) - result = self._unpack_response(response) - return result diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.py deleted file mode 100644 index 7617524a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector.py +++ /dev/null @@ -1,78 +0,0 @@ -import atexit -import threading -import time - -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import ( - convert_arguments_from_protobuf_to_python, -) -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import ( - QueueBasedIterableObserver, -) - - -class KiwoomOpenApiPlusServiceClientSideSignalConnector: - def __init__(self, stub, name, executor): - self._stub = stub - self._name = name - self._executor = executor - self._lock = threading.RLock() - self._observers = {} - - atexit.register(self.shutdown) - - def __del__(self): - atexit.unregister(self.shutdown) - - def _stop_observer(self, observer): - request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() - request.stop_listen_request.time = time.time() - observer.on_next(request) - observer.on_completed() - - def _get_observer(self, callback, default=None): - return self._observers.setdefault(self._name, {}).get(callback, default) - - def _remove_observer(self, callback): - with self._lock: - observer = self._get_observer(callback) - if observer: - self._stop_observer(observer) - del self._observers[self._name][callback] - return observer - - def _add_observer(self, callback): - with self._lock: - self._remove_observer(callback) - observer = QueueBasedIterableObserver() - self._observers[self._name][callback] = observer - return observer - - def shutdown(self): - with self._lock: - for _name, observers in self._observers.items(): - for _callback, observer in observers.items(): - self._stop_observer(observer) - - def connect(self, callback): - with self._lock: - observer = self._add_observer(callback) - - def fn(): - request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() - request.listen_request.slots.append(self._name) - observer.on_next(request) - observer_iterator = iter(observer) - response_iterator = self._stub.BidirectionalListen(observer_iterator) - for response in response_iterator: - args = convert_arguments_from_protobuf_to_python(response.arguments) - callback(*args) - request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() - request.handled_request.time = time.time() - observer.on_next(request) - - _future = self._executor.submit(fn) - - def disconnect(self, callback): - with self._lock: - self._remove_observer(callback) diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.py deleted file mode 100644 index 0f7eda7e..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper.py +++ /dev/null @@ -1,1461 +0,0 @@ -import datetime -import logging -import re - -import pandas as pd - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature import ( - KiwoomOpenApiPlusDispatchSignature, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature import ( - KiwoomOpenApiPlusEventHandlerSignature, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetUniversalMixin, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable import ( - KiwoomOpenApiPlusServiceClientSideDynamicCallable, -) -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector import ( - KiwoomOpenApiPlusServiceClientSideSignalConnector, -) -from koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous import ( - PipeableMultiThreadedRendezvous, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusServiceClientStubCoreWrapper( - KiwoomOpenApiPlusQAxWidgetUniversalMixin -): - """ - KiwoomOpenApiPlusServiceServicer 에서 구현되어 이후 Stub 을 통해 제공되는 - RPC 들을 클라이언트에서 좀 더 쉽게 사용하기 위한 래퍼 함수들을 제공합니다. - """ - - METHOD_NAMES = KiwoomOpenApiPlusDispatchSignature.names() - EVENT_NAMES = KiwoomOpenApiPlusEventHandlerSignature.names() - - def __init__(self, stub, executor): - self._stub = stub - self._executor = executor - - # Set methods as attributes - for method_name in self.METHOD_NAMES: - dynamic_callable = KiwoomOpenApiPlusServiceClientSideDynamicCallable( - self._stub, method_name - ) - setattr(self, method_name, dynamic_callable) - - # Set signals as attributes - for event_name in self.EVENT_NAMES: - signal_connector = KiwoomOpenApiPlusServiceClientSideSignalConnector( - self._stub, event_name, self._executor - ) - setattr(self, event_name, signal_connector) - - def __getattr__(self, name): - return getattr(self._stub, name) - - def Call(self, name, *args): - """ - 임의의 함수 호출을 위한 RPC 입니다. - - 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 - 호출결과를 응답 메시지를 통해 전달합니다. - - 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. - """ - return KiwoomOpenApiPlusServiceClientSideDynamicCallable(self._stub, name)( - *args - ) - - def LoginCall(self, credentials=None): - """ - 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. - - CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - request = KiwoomOpenApiPlusService_pb2.LoginRequest() - if credentials is not None: - request.credentials.user_id = credentials.get("user_id") - request.credentials.user_password = credentials.get("user_password") - request.credentials.cert_password = credentials.get("cert_password") - request.credentials.is_simulation = credentials.get("is_simulation") - account_passwords = credentials.get("account_passwords") - for account_no, account_password in account_passwords.items(): - request.credentials.account_passwords[account_no] = account_password - for response in self._stub.LoginCall(request): - errcode = response.arguments[0].long_value - return errcode - - def TransactionCall(self, rqname, trcode, scrno, inputs, stop_condition=None): - """ - TR 요청에 해당하는 RPC 입니다. - - CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 - 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. - 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. - - 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 - 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. - - 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 - 내부적으로 호출됩니다. - - 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 - 대기시간이 발생할 수 있습니다. - - 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. - 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, - TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. - """ - request = KiwoomOpenApiPlusService_pb2.TransactionRequest() - request.request_name = rqname - request.transaction_code = trcode - request.screen_no = scrno or "" - for k, v in inputs.items(): - request.inputs[k] = v - if stop_condition: - request.stop_condition.name = stop_condition.get("name", "") - request.stop_condition.value = str(stop_condition.get("value", "")) - request.stop_condition.comparator = { - "<=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO, - "<": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN, - ">=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO, - ">": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN, - "==": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO, - "!=": KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO, - }.get(stop_condition.get("comparator", "<=")) - return self._stub.TransactionCall(request) - - def OrderCall( - self, - rqname, - scrno, - account, - order_type, - code, - quantity, - price, - quote_type, - original_order_no=None, - ): - """ - 주문 요청에 해당하는 RPC 입니다. - - SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 - 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. - - 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. - 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. - - 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. - - 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. - - 거래 구분: - - 00: 지정가 - - 03: 시장가 - - 05: 조건부지정가 - - 06: 최유리지정가 - - 07: 최우선지정가 - - 10: 지정가IOC - - 13: 시장가IOC - - 16: 최유리IOC - - 20: 지정가FOK - - 23: 시장가FOK - - 26: 최유리FOK - - 61: 장전시간외종가 - - 62: 시간외단일가매매 - - 81: 장후시간외종가 - - ※ 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. - - 주문 유형: - - 1: 신규매수 - - 2: 신규매도 - - 3: 매수취소 - - 4: 매도취소 - - 5: 매수정정 - - 6: 매도정정 - - Args: - rqname (str): 사용자 구분 요청명 - scrno (str): 화면번호 (4자리) - account (str): 계좌번호 (10자리) - order_type (int): 주문유형 (1:신규매수, 2:신규매도, 3:매수취소, 4:매도취소, 5:매수정정, 6:매도정정) - code (str): 종목코드 (6자리) - quantity (int): 주문수량 - price (int): 주문단가 - quote_type (str): 거래구분 (혹은 호가구분) - original_order_no (str): 원주문번호, 신규주문에는 공백 입력, 정정/취소시 입력합니다. - """ - request = KiwoomOpenApiPlusService_pb2.OrderRequest() - request.request_name = rqname or "" - request.screen_no = str(scrno).zfill(4) if scrno else "" - request.account_no = str(account) if account else "" - request.order_type = int(order_type) if order_type else 0 - request.code = code or "" - request.quantity = int(quantity) if quantity else 0 - request.price = int(price) if price else 0 - request.quote_type = quote_type or "" - request.original_order_no = original_order_no or "" - return self._stub.OrderCall(request) - - def RealCall( - self, - scrno, - codes, - fids, - opt_type=None, - infer_fids=False, - readable_names=False, - fast_parse=False, - ): - """ - 실시간 데이터 요청에 해당하는 RPC 입니다. - - SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 - 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 - 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. - 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. - - 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 - 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. - 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. - """ - request = KiwoomOpenApiPlusService_pb2.RealRequest() - if scrno is None: - scrnos = [] - elif isinstance(scrno, str): - scrnos = [scrno] - else: - scrnos = scrno - fids = [int(fid) for fid in fids] - if opt_type is None: - opt_type = "0" - request.screen_no.extend(scrnos) - request.code_list.extend(codes) - request.fid_list.extend(fids) - request.opt_type = opt_type - request.flags.infer_fids = infer_fids - request.flags.readable_names = readable_names - request.flags.fast_parse = fast_parse - return self._stub.RealCall(request) - - def LoadConditionCall(self): - """ - 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. - - GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - request = KiwoomOpenApiPlusService_pb2.LoadConditionRequest() - for response in self._stub.LoadConditionCall(request): - ret = response.arguments[0].long_value - msg = response.arguments[1].string_value - return (ret, msg) - - def ConditionCall( - self, - scrno, - condition_name, - condition_index, - search_type, - with_info=False, - is_future_option=False, - request_name=None, - ): - """ - 조건검색 기능에 해당하는 RPC 입니다. - - SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 - 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - request = request = KiwoomOpenApiPlusService_pb2.ConditionRequest() - request.screen_no = scrno or "" - request.condition_name = condition_name - request.condition_index = condition_index - request.search_type = search_type - request.flags.with_info = with_info - request.flags.is_future_option = is_future_option - if request_name is not None: - request.request_name = request_name - return self._stub.ConditionCall(request) - - def SetLogLevel(self, level, logger=""): - """ - 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. - """ - request = KiwoomOpenApiPlusService_pb2.SetLogLevelRequest() - request.level = level - request.logger = logger - return self._stub.SetLogLevel(request) - - def _LoadConditionUsingCall(self): - return self.Call("LoadCondition") - - def LoadCondition(self): - """ - 조건검색 관련 조건식을 불러옵니다. - """ - return self._LoadConditionUsingCall() - - def _IsConditionLoadedUsingCall(self): - return self.Call("IsConditionLoaded") - - def IsConditionLoaded(self): - """ - 조건식이 로드 되었는지 여부를 반환합니다. - """ - return self._IsConditionLoadedUsingCall() - - def _EnsureConditionLoadedUsingCall(self, force=False): - return self.Call("EnsureConditionLoaded", force) - - def EnsureConditionLoaded(self, force=False): - """ - 조건식이 로드됨을 보장하도록 합니다. - - 이미 조건식을 불러온 경우 별다른 처리를 하지 않습니다. - 조건식을 불러오지 않았다면 조건식을 불러오도록 처리합니다. - """ - return self._EnsureConditionLoadedUsingCall(force) - - def _RateLimitedCommRqDataUsingCall( - self, rqname, trcode, prevnext, scrno, inputs=None - ): - return self.Call( - "RateLimitedCommRqData", rqname, trcode, prevnext, scrno, inputs - ) - - def RateLimitedCommRqData(self, rqname, trcode, prevnext, scrno, inputs=None): - """ - CommRqData() 와 동일하지만 호출제한 회피를 위한 함수입니다. - 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. - """ - self._RateLimitedCommRqDataUsingCall(rqname, trcode, prevnext, scrno, inputs) - - def _RateLimitedSendConditionUsingCall( - self, scrno, condition_name, condition_index, search_type - ): - return self.Call( - "RateLimitedSendCondition", - scrno, - condition_name, - condition_index, - search_type, - ) - - def RateLimitedSendCondition( - self, scrno, condition_name, condition_index, search_type - ): - """ - SendCondition() 과 동일하지만 호출제한 회피를 위한 함수입니다. - 필요에 따라 호출제한을 회피하기 위해 실제 호출 전 대기할 수 있습니다. - """ - return self._RateLimitedSendConditionUsingCall( - scrno, condition_name, condition_index, search_type - ) - - -class KiwoomOpenApiPlusServiceClientStubExtendedWrapper( - KiwoomOpenApiPlusServiceClientStubCoreWrapper, Logging -): - """ - 제공되는 RPC 들을 활용한 여러 사용 케이스들을 구현합니다. - """ - - def _RemoveLeadingZerosForNumber(self, value, width=0): - remove = False - if width is None: - remove = False - elif isinstance(width, int) and (width == 0 or len(value) == width): - remove = True - elif hasattr(width, "__contains__") and len(value) in width: - remove = True - if remove: - return re.sub(r"^\s*([+-]?)[0]+([0-9]+(.[0-9]+)?)\s*$", r"\1\2", value) - return value - - def _RemoveLeadingZerosForNumbersInValues(self, values, width=0): - return [self._RemoveLeadingZerosForNumber(value, width) for value in values] - - def _ParseTransactionCallResponses(self, responses, remove_zeros_width=None): - single_output = None - columns = [] - records = [] - for response in responses: - if single_output is None: - single_output = dict( - zip( - response.single_data.names, - self._RemoveLeadingZerosForNumbersInValues( - response.single_data.values, remove_zeros_width - ), - ) - ) - if not columns: - columns = response.multi_data.names - for values in response.multi_data.values: - records.append( - self._RemoveLeadingZerosForNumbersInValues( - values.values, remove_zeros_width - ) - ) - single = pd.Series(single_output, dtype=object) - multi = pd.DataFrame.from_records(records, columns=columns) - return single, multi - - def GetStockBasicInfoAsDict(self, code, rqname=None, scrno=None): - """ - 주식 종목의 기본정보를 딕셔너리 형태로 반환합니다. - - TR: OPT10001 - """ - if rqname is None: - rqname = "주식기본정보요청" - trcode = "opt10001" - inputs = {"종목코드": code} - for response in self.TransactionCall(rqname, trcode, scrno, inputs): - names = response.single_data.names - values = response.single_data.values - result = dict(zip(names, values)) - return result - - def GetStockBasicInfoAsSeries(self, code, rqname=None, scrno=None): - """ - 주식 종목의 기본정보를 pd.Series 형태로 반환합니다. - - TR: OPT10001 - """ - dic = self.GetStockBasicInfoAsDict(code, rqname, scrno) - series = pd.Series(dic) - return series - - def GetStockQuoteInfoAsDataFrame(self, codes=None, rqname=None, scrno=None): - """ - 복수개의 주식 종목들의 기본정보를 pd.DataFrame 형태로 반환합니다. - - TR: OPTKWFID - """ - if codes is None: - codes = self.GetGeneralCodeList() - elif isinstance(codes, str): - codes = [codes] - if rqname is None: - rqname = "관심종목정보요청" - trcode = "OPTKWFID" - columns = [] - records = [] - inputs = {"종목코드": ";".join(codes)} - for response in self.TransactionCall(rqname, trcode, scrno, inputs): - if not columns: - columns = response.multi_data.names - for values in response.multi_data.values: - records.append(values.values) - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetTickStockDataAsDataFrame( - self, - code, - interval, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 틱 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10079 - """ - if interval is not None: - interval = int(interval) - interval = str(interval) - - date_format = "%Y%m%d%H%M%S" - date_column_name = "체결시간" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식틱차트조회요청" - trcode = "opt10079" - inputs = { - "종목코드": code, - "틱범위": interval, - "수정주가구분": "1" if adjusted_price else "0", - } - - columns = [] - records = [] - - date_column_index = None - should_compare_start = start_date is not None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - if should_compare_start and date_column_index is not None: - date = values.values[date_column_index] - if date > start_date: - # 해당 TR 은 기준일자를 INPUT 으로 설정할 수 없는 이유로 - # 일단 가장 최근부터 차례대로 가져오고 클라이언트에서 요청보다 최근 데이터는 버림 - # 클라이언트 말고 서버에서 미리 처리해서 데이터를 보내지조차 않아야 할지?? - continue - else: - should_compare_start = False - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetMinuteStockDataAsDataFrame( - self, - code, - interval, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 분 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10080 - """ - if interval is not None: - interval = int(interval) - interval = str(interval) - - date_format = "%Y%m%d%H%M%S" - date_column_name = "체결시간" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식분봉차트조회요청" - trcode = "opt10080" - inputs = { - "종목코드": code, - "틱범위": interval, - "수정주가구분": "1" if adjusted_price else "0", - } - - columns = [] - records = [] - - date_column_index = None - should_compare_start = start_date is not None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - if should_compare_start and date_column_index is not None: - date = values.values[date_column_index] - if date > start_date: - # 해당 TR 은 기준일자를 INPUT 으로 설정할 수 없는 이유로 - # 일단 가장 최근부터 차례대로 가져오고 클라이언트에서 요청보다 최근 데이터는 버림 - # 클라이언트 말고 서버에서 미리 처리해서 데이터를 보내지조차 않아야 할지?? - continue - else: - should_compare_start = False - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetDailyStockDataAsDataFrame( - self, - code, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 일 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10081 - """ - date_format = "%Y%m%d" - date_column_name = "일자" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식일봉차트조회요청" - - trcode = "opt10081" - inputs = { - "종목코드": code, - "수정주가구분": "1" if adjusted_price else "0", - } - if start_date is not None: - inputs["기준일자"] = start_date - - columns = [] - records = [] - - date_column_index = None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetWeeklyStockDataAsDataFrame( - self, - code, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 주 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10082 - """ - date_format = "%Y%m%d" - date_column_name = "일자" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식주봉차트조회요청" - - trcode = "opt10082" - inputs = { - "종목코드": code, - "수정주가구분": "1" if adjusted_price else "0", - } - if start_date is not None: - inputs["기준일자"] = start_date - if end_date is not None: - inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... - - columns = [] - records = [] - date_column_index = None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetMonthlyStockDataAsDataFrame( - self, - code, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 월 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10083 - """ - date_format = "%Y%m%d" - date_column_name = "일자" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식월봉차트조회요청" - - trcode = "opt10083" - inputs = { - "종목코드": code, - "수정주가구분": "1" if adjusted_price else "0", - } - if start_date is not None: - inputs["기준일자"] = start_date - if end_date is not None: - inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... - - columns = [] - records = [] - date_column_index = None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetYearlyStockDataAsDataFrame( - self, - code, - start_date=None, - end_date=None, - include_end=False, - adjusted_price=False, - rqname=None, - scrno=None, - ): - """ - 년 단위 차트 데이터를 pd.DataFrame 형태로 반환합니다. - - TR: OPT10094 - """ - date_format = "%Y%m%d" - date_column_name = "일자" - - if isinstance(start_date, datetime.datetime): - start_date = start_date.strftime(date_format) - - if end_date is not None: - if isinstance(end_date, datetime.datetime): - end_date = end_date.strftime(date_format) - stop_condition = { - "name": date_column_name, - "value": end_date, - } - if include_end: - stop_condition["comparator"] = "<" - else: - stop_condition = None - - if rqname is None: - rqname = "주식년봉차트조회요청" - - trcode = "opt10094" - inputs = { - "종목코드": code, - "수정주가구분": "1" if adjusted_price else "0", - } - if start_date is not None: - inputs["기준일자"] = start_date - if end_date is not None: - inputs["끝일자"] = end_date # 딱히 끝일자가 생각하는대로 안먹히는듯... - - columns = [] - records = [] - date_column_index = None - - for response in self.TransactionCall( - rqname, trcode, scrno, inputs, stop_condition=stop_condition - ): - if not columns: - columns = list(response.multi_data.names) - if date_column_name in columns: - date_column_index = columns.index(date_column_name) - for values in response.multi_data.values: - records.append(values.values) - - if self.logger.isEnabledFor(logging.DEBUG): - nrows = len(response.multi_data.values) - if nrows > 0: - from_date = response.multi_data.values[0].values[date_column_index] - to_date = response.multi_data.values[-1].values[date_column_index] - from_date = datetime.datetime.strptime(from_date, date_format) - to_date = datetime.datetime.strptime(to_date, date_format) - self.logger.debug( - "Received %d records from %s to %s for code %s", - nrows, - from_date, - to_date, - code, - ) - - df = pd.DataFrame.from_records(records, columns=columns) - return df - - def GetDepositInfo( - self, account_no, lookup_type=None, with_multi=False, rqname=None, scrno=None - ): - """ - 계좌의 예수금 정보를 반환합니다. - - TR: OPW00001 - - 조회구분 = 3:추정조회, 2:일반조회 - """ - if rqname is None: - rqname = "예수금상세현황요청" - trcode = "opw00001" - inputs = { - "계좌번호": account_no, - "비밀번호": "", - "비밀번호입력매체구분": "00", - "조회구분": "2" if lookup_type is None else lookup_type, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - single, multi = self._ParseTransactionCallResponses(responses, [12, 15]) - if with_multi: - return single, multi - else: - return single - - def GetStockQuotes(self, code, rqname=None, scrno=None): - """ - 주식의 호가정보를 반환합니다. - - TR: OPT10004 - """ - if rqname is None: - rqname = "주식호가요청" - trcode = "opt10004" - inputs = { - "종목코드": code, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - single, _multi = self._ParseTransactionCallResponses(responses, [12, 15]) - return single - - def GetOrderLogAsDataFrame1( - self, - account_no, - order_type=None, - status_type=None, - code=None, - rqname=None, - scrno=None, - ): - """ - 미체결 주문 정보를 반환합니다. - - TR: OPT10075 - - 계좌번호 = 전문 조회할 보유계좌번호 - 전체종목구분 = 0:전체, 1:종목 - 매매구분 = 0:전체, 1:매도, 2:매수 - 종목코드 = 전문 조회할 종목코드 - 체결구분 = 0:전체, 2:체결, 1:미체결 - """ - - if rqname is None: - rqname = "실시간미체결요청" - trcode = "opt10075" - inputs = { - "계좌번호": account_no, - "전체종목구분": "0" if code is None else "1", - "매매구분": "0" if order_type is None else order_type, - "종목코드": "" if code is None else code, - "체결구분": "0" if status_type is None else status_type, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - _single, multi = self._ParseTransactionCallResponses(responses) - return multi - - def GetOrderLogAsDataFrame2( - self, - account_no, - order_type=None, - status_type=None, - code=None, - order_no=None, - rqname=None, - scrno=None, - ): - """ - 주문 체결 정보를 반환합니다. - - TR: OPT10076 - - 종목코드 = 전문 조회할 종목코드 - 조회구분 = 0:전체, 1:종목 - 매도수구분 = 0:전체, 1:매도, 2:매수 - 계좌번호 = 전문 조회할 보유계좌번호 - 비밀번호 = 사용안함(공백) - 주문번호 = 조회할 주문번호 - 체결구분 = 0:전체, 2:체결, 1:미체결 - """ - - if rqname is None: - rqname = "실시간체결요청" - trcode = "opt10076" - inputs = { - "종목코드": "" if code is None else code, - "조회구분": "0" if code is None else "1", - "매도수구분": "0" if order_type is None else order_type, - "계좌번호": account_no, - "비밀번호": "", - "주문번호": "" if order_no is None else order_no, - "체결구분": "0" if status_type is None else status_type, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - _single, multi = self._ParseTransactionCallResponses(responses) - return multi - - def GetOrderLogAsDataFrame3( - self, - account_no, - date=None, - sort_type=None, - asset_type=None, - order_type=None, - code=None, - starting_order_no=None, - rqname=None, - scrno=None, - ): - """ - 계좌별 주문 체결 내역을 반환합니다. - - TR: OPW00007 - - 주문일자 = YYYYMMDD (20170101 연도4자리, 월 2자리, 일 2자리 형식) - 계좌번호 = 전문 조회할 보유계좌번호 - 비밀번호 = 사용안함(공백) - 비밀번호입력매체구분 = 00 - 조회구분 = 1:주문순, 2:역순, 3:미체결, 4:체결내역만 - 주식채권구분 = 0:전체, 1:주식, 2:채권 - 매도수구분 = 0:전체, 1:매도, 2:매수 - 종목코드 - 시작주문번호 - """ - - if rqname is None: - rqname = "계좌별주문체결내역상세요청" - trcode = "opw00007" - if date is None: - now = datetime.datetime.now() - market_start_time = now.replace(hour=8, minute=20, second=0, microsecond=0) - if now < market_start_time: - now = now - datetime.timedelta(days=1) - date = now.strftime("%Y%m%d") - inputs = { - "주문일자": date, - "계좌번호": account_no, - "비밀번호": "", - "비밀번호입력매체구분": "00", - "조회구분": "1" if sort_type is None else sort_type, - "주식채권구분": "0" if asset_type is None else asset_type, - "매도수구분": "0" if order_type is None else order_type, - "종목코드": "" if code is None else code, - "시작주문번호": "" if starting_order_no is None else starting_order_no, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - _single, multi = self._ParseTransactionCallResponses(responses, 10) - return multi - - def GetAccountRateOfReturnAsDataFrame(self, account_no, rqname=None, scrno=None): - """ - 계좌별 수익률 정보를 반환합니다. - - TR: OPT10085 - """ - if rqname is None: - rqname = "계좌수익률요청" - trcode = "opt10085" - inputs = { - "계좌번호": account_no, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - _single, multi = self._ParseTransactionCallResponses(responses, 10) - return multi - - def GetAccountEvaluationStatusAsSeriesAndDataFrame( - self, account_no, include_delisted=True, rqname=None, scrno=None - ): - """ - 계좌의 평가 현황 정보를 반환합니다. - - TR: OPW00004 - """ - if rqname is None: - rqname = "계좌평가현황요청" - trcode = "opw00004" - inputs = { - "계좌번호": account_no, - "비밀번호": "", - "상장폐지조회구분": "0" if include_delisted else "1", - "비밀번호입력매체구분": "00", - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - single, multi = self._ParseTransactionCallResponses(responses, 12) - return single, multi - - def GetAccountExecutionBalanceAsSeriesAndDataFrame( - self, account_no, rqname=None, scrno=None - ): - """ - 계좌의 체결 잔고 정보를 반환합니다. - - TR: OPW00005 - - 모의투자에서는 지원하지 않는 TR 입니다. - """ - server = self.GetServerGubun() - if server == "1": - self.logger.warning("Not supported for simulated investment") - if rqname is None: - rqname = "체결잔고요청" - if scrno is None: - scrno = "1010" - trcode = "opw00005" # 모의투자에서 지원하지 않는 TR - inputs = { - "계좌번호": account_no, - "비밀번호": "", - "비밀번호입력매체구분": "00", - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - single, multi = self._ParseTransactionCallResponses(responses, 0) - return single, multi - - def GetAccountEvaluationBalanceAsSeriesAndDataFrame( - self, account_no, lookup_type=None, rqname=None, scrno=None - ): - """ - 계좌의 평가 잔고 내역 정보를 반환합니다. - - TR: OPW00018 - - 조회구분 = 1:합산, 2:개별 - - [ 주의 ] - "수익률%" 데이터는 모의투자에서는 소숫점표현, 실거래서버에서는 소숫점으로 변환 필요 합니다. - """ - if rqname is None: - rqname = "계좌평가잔고내역요청" - trcode = "opw00018" - inputs = { - "계좌번호": account_no, - "비밀번호": "", - "비밀번호입력매체구분": "00", - "조회구분": "2" if lookup_type is None else str(lookup_type), - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - single, multi = self._ParseTransactionCallResponses(responses, [12, 15]) - return single, multi - - def GetMarketPriceInfo(self, code, rqname=None, scrno=None): - """ - 종목의 시세표성 정보를 반환합니다. - - TR: OPT10007 - """ - if rqname is None: - rqname = "시세표성정보요청" - trcode = "opt10007" - inputs = { - "종목코드": code, - } - responses = self.TransactionCall(rqname, trcode, scrno, inputs) - _single, multi = self._ParseTransactionCallResponses(responses) - single = multi.iloc[0] - return single - - def GetRealDataForCodesAsStream( - self, - codes, - fids=None, - opt_type=None, - screen_no=None, - infer_fids=False, - readable_names=False, - fast_parse=False, - ): - """ - 실시간 데이터를 요청하고 스트림 형태로 반환받습니다. - """ - if isinstance(codes, str): - codes = [codes] - if fids is None: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - - fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") - if opt_type is None: - opt_type = "0" - assert opt_type in ["0", "1"], "opt_type should be either 0 or 1" - responses = self.RealCall( - screen_no, codes, fids, opt_type, infer_fids, readable_names, fast_parse - ) - return responses - - def GetCodeListByCondition( - self, - condition_name, - condition_index=None, - with_info=False, - is_future_option=False, - request_name=None, - screen_no=None, - ): - """ - 주어진 조건식으로 조건검색을 수행하고 - 검색된 종목의 종목코드를 리스트로 반환받습니다. - - 파라미터 중 with_info 가 True 로 설정된 경우, - 검색된 종목들에 대한 기본 정보도 추가로 같이 반환됩니다. - """ - search_type = 0 - - if condition_index is None: - condition_names = self.GetConditionNameListAsList() - condition_indices = {item[1]: item[0] for item in condition_names} - condition_index = condition_indices[condition_name] - - codes = [] - - single_output = None - columns = [] - records = [] - remove_zeros_width = None - - for response in self.ConditionCall( - screen_no, - condition_name, - condition_index, - search_type, - with_info, - is_future_option, - request_name, - ): - if response.name == "OnReceiveTrCondition": - code_list = response.arguments[1].string_value - code_list = code_list.rstrip(";").split(";") if code_list else [] - codes.extend(code_list) - elif response.name == "OnReceiveTrData": - if single_output is None: - single_output = dict( - zip( - response.single_data.names, - self._RemoveLeadingZerosForNumbersInValues( - response.single_data.values, remove_zeros_width - ), - ) - ) - if not columns: - columns = response.multi_data.names - for values in response.multi_data.values: - records.append( - self._RemoveLeadingZerosForNumbersInValues( - values.values, remove_zeros_width - ) - ) - else: - raise ValueError("Unexpected event handler name %s" % response.name) - - _single = pd.Series(single_output, dtype=object) - multi = pd.DataFrame.from_records(records, columns=columns) - - if with_info: - return codes, multi - else: - return codes - - def _GetCodeListByConditionAsStream_GeneratorFunc(self, responses, with_info=False): - for response in responses: - if response.name == "OnReceiveTrCondition": - code_list = response.arguments[1].string_value - code_list = code_list.rstrip(";").split(";") if code_list else [] - inserted = code_list - deleted = [] - if with_info: - info = None - yield inserted, deleted, info - else: - yield inserted, deleted - elif response.name == "OnReceiveRealCondition": - code = response.arguments[0].string_value - condition_type = response.arguments[1].string_value - inserted = [] - deleted = [] - if condition_type == "I": - inserted.append(code) - elif condition_type == "D": - deleted.append(code) - else: - raise ValueError("Unexpected condition type %s" % condition_type) - if with_info: - info = None - yield inserted, deleted, info - else: - yield inserted, deleted - elif response.name == "OnReceiveTrData": - single_output = None - columns = [] - records = [] - remove_zeros_width = None - if single_output is None: - single_output = dict( - zip( - response.single_data.names, - self._RemoveLeadingZerosForNumbersInValues( - response.single_data.values, remove_zeros_width - ), - ) - ) - if not columns: - columns = response.multi_data.names - for values in response.multi_data.values: - records.append( - self._RemoveLeadingZerosForNumbersInValues( - values.values, remove_zeros_width - ) - ) - _single = pd.Series(single_output, dtype=object) - multi = pd.DataFrame.from_records(records, columns=columns) - inserted = [] - deleted = [] - if with_info: - info = multi - yield inserted, deleted, info - else: - raise RuntimeError( - "Unexpected, OnReceiveTrData event with with_info=False ???" - ) - else: - raise ValueError("Unexpected event handler name %s" % response.name) - - def GetCodeListByConditionAsStream( - self, - condition_name, - condition_index=None, - with_info=False, - is_future_option=False, - request_name=None, - screen_no=None, - old_behavior=False, - ): - """ - 주어진 조건식을 실시간 조건검색으로 등록합니다. - 이후 발생하는 이벤트들을 스트림 형태로 제공합니다. - - 최초 검색결과는 OnReceiveTrCondition() 이벤트로 반환되며 - 이후 종목의 추가/제외는 OnReceiveRealCondition() 이벤트로 반환됩니다. - - 만약 with_info 가 True 로 설정된 경우, - 검색된 종목마다 추가적인 정보가 OnReceiveTrData() 이벤트를 통해 반환됩니다. - """ - search_type = 1 - - if condition_index is None: - condition_names = self.GetConditionNameListAsList() - condition_indices = {item[1]: item[0] for item in condition_names} - condition_index = condition_indices[condition_name] - - responses = self.ConditionCall( - screen_no, - condition_name, - condition_index, - search_type, - with_info, - is_future_option, - request_name, - ) - - if not old_behavior: - return responses - - stream = PipeableMultiThreadedRendezvous(responses) - stream = stream.pipe( - lambda responses: self._GetCodeListByConditionAsStream_GeneratorFunc( - responses, with_info=with_info - ) - ) - - return stream - - -class KiwoomOpenApiPlusServiceClientStubWrapper( - KiwoomOpenApiPlusServiceClientStubExtendedWrapper -): - """ - KiwoomOpenApiPlusServiceClientStubCoreWrapper, KiwoomOpenApiPlusServiceClientStubExtendedWrapper 의 구현 및 - KiwoomOpenApiPlusQAxWidgetUniversalMixin 의 구현들까지 최종적으로 포함된 - KiwoomOpenApiPlusServiceClientStub 객체를 위한 Mixin 래퍼 클래스 입니다. - """ diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.py deleted file mode 100644 index 3bf784ad..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils.py +++ /dev/null @@ -1,25 +0,0 @@ -def convert_arguments_from_protobuf_to_python(arguments): - args = [] - for argument in arguments: - if argument.HasField("string_value"): - args.append(argument.string_value) - elif argument.HasField("bool_value"): - args.append(argument.bool_value) - elif argument.HasField("long_value"): - args.append(argument.long_value) - else: - raise ValueError("No expecting field found.") - return args - - -def convert_arguments_from_python_to_protobuf(arguments, arguments_message): - for i, arg in enumerate(arguments): - if isinstance(arg, str): - arguments_message.add().string_value = arg - elif isinstance(arg, bool): - arguments_message.add().bool_value = arg - elif isinstance(arg, int): - arguments_message.add().long_value = arg - else: - raise TypeError("Unexpected type for argument %d: %s" % (i, type(arg))) - return arguments_message diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.py deleted file mode 100644 index 3f2d5897..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer.py +++ /dev/null @@ -1,151 +0,0 @@ -import inspect - -from concurrent.futures import ThreadPoolExecutor - -import grpc - -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2_grpc -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer import ( - KiwoomOpenApiPlusServiceServicer, -) -from koapy.config import config -from koapy.utils.logging.Logging import Logging -from koapy.utils.networking import find_free_port_for_host, is_in_private_network - - -class KiwoomOpenApiPlusServiceServer(Logging): - def __init__( - self, - control, - host=None, - port=None, - credentials=None, - **kwargs, - ): - if host is None: - host = config.get_string( - "koapy.backend.kiwoom_open_api_plus.grpc.host", "localhost" - ) - host = config.get_string( - "koapy.backend.kiwoom_open_api_plus.grpc.server.host", host - ) - if port is None: - port = config.get_int("koapy.backend.kiwoom_open_api_plus.grpc.port", 0) - port = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.server.port", port - ) - - if port == 0: - port = find_free_port_for_host(host) - self.logger.info( - "Using one of the free ports, final address would be %s:%d", host, port - ) - - self._control = control - self._host = host - self._port = port - self._credentials = credentials - self._kwargs = dict(kwargs) - - self._servicer = KiwoomOpenApiPlusServiceServicer(self._control) - self._address = self._host + ":" + str(self._port) - - grpc_server_signature = inspect.signature(grpc.server) - grpc_server_params = list(grpc_server_signature.parameters.keys()) - grpc_server_kwargs = { - k: v for k, v in self._kwargs.items() if k in grpc_server_params - } - grpc_server_bound_arguments = grpc_server_signature.bind_partial( - **grpc_server_kwargs - ) - if grpc_server_bound_arguments.arguments.get("thread_pool") is None: - thread_pool_signature = inspect.signature(ThreadPoolExecutor) - thread_pool_params = list(thread_pool_signature.parameters.keys()) - thread_pool_kwargs = { - k: v for k, v in self._kwargs.items() if k in thread_pool_params - } - thread_pool_bound_arguments = thread_pool_signature.bind( - **thread_pool_kwargs - ) - if thread_pool_bound_arguments.arguments.get("max_workers") is None: - max_workers = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.server.max_workers", 8 - ) - thread_pool_bound_arguments.arguments["max_workers"] = max_workers - thread_pool = ThreadPoolExecutor( - *thread_pool_bound_arguments.args, - **thread_pool_bound_arguments.kwargs, - ) - grpc_server_bound_arguments.arguments["thread_pool"] = thread_pool - self._thread_pool = thread_pool - else: - self._thread_pool = grpc_server_bound_arguments.arguments["thread_pool"] - - self._grpc_server_bound_arguments = grpc_server_bound_arguments - - self._server = None - self._server_started = False - self._server_stopped = False - - self.reinitialize_server() - - def reinitialize_server(self): - if self._server is not None: - self.stop() - self.wait_for_termination() - - self._server = grpc.server( - *self._grpc_server_bound_arguments.args, - **self._grpc_server_bound_arguments.kwargs, - ) - self._server_started = False - self._server_stopped = False - - KiwoomOpenApiPlusService_pb2_grpc.add_KiwoomOpenApiPlusServiceServicer_to_server( - self._servicer, self._server - ) - - if self._credentials is None: - if not is_in_private_network(self._host): - self.logger.warning( - "Adding insecure port %s to server, but the address is not private.", - self._address, - ) - self._server.add_insecure_port(self._address) - else: - self._server.add_secure_port(self._address, self._credentials) - - def get_host(self): - return self._host - - def get_port(self): - return self._port - - def start(self): - if self._server_started and self._server_stopped: - self.reinitialize_server() - if not self._server_started: - self._server.start() - self._server_started = True - - def wait_for_termination(self, timeout=None): - return self._server.wait_for_termination(timeout) - - def is_running(self): - return self.wait_for_termination(1) - - def stop(self, grace=None): - event = self._server.stop(grace) - self._server_stopped = True - return event - - def __getattr__(self, name): - return getattr(self._server, name) - - def __enter__(self): - self.start() - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.stop() - self.wait_for_termination() diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.py deleted file mode 100644 index b7f05fb1..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer.py +++ /dev/null @@ -1,368 +0,0 @@ -import logging - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import ( - KiwoomOpenApiPlusEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager import ( - KiwoomOpenApiPlusScreenManager, -) -from koapy.backend.kiwoom_open_api_plus.grpc import ( - KiwoomOpenApiPlusService_pb2, - KiwoomOpenApiPlusService_pb2_grpc, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler import ( - KiwoomOpenApiPlusConditionEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers import ( - KiwoomOpenApiPlusAllEventHandler, - KiwoomOpenApiPlusSomeBidirectionalEventHandler, - KiwoomOpenApiPlusSomeEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler import ( - KiwoomOpenApiPlusKwTrEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler import ( - KiwoomOpenApiPlusLoadConditionEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler import ( - KiwoomOpenApiPlusLoginEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler import ( - KiwoomOpenApiPlusAllOrderEventHandler, - KiwoomOpenApiPlusOrderEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler import ( - KiwoomOpenApiPlusBidirectionalRealEventHandler, - KiwoomOpenApiPlusRealEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler import ( - KiwoomOpenApiPlusTrEventHandler, -) -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils import ( - convert_arguments_from_protobuf_to_python, -) - - -class KiwoomOpenApiPlusServiceServicer( - KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer -): - """ - KiwoomOpenApiPlusService RPC 의 구현체 입니다. - """ - - def __init__(self, control): - super().__init__() - - self._control = control - self._screen_manager = KiwoomOpenApiPlusScreenManager(self._control) - - @property - def control(self): - return self._control - - @property - def screen_manager(self): - return self._screen_manager - - # 1. rpcs for general function calls - - def Call(self, request, context): - """ - 임의의 함수 호출을 위한 RPC 입니다. - - 함수의 이름과 파라미터를 요청 메시지를 통해 전달받아 서버측에서 해당 함수를 호출하고 - 호출결과를 응답 메시지를 통해 전달합니다. - - 함수의 파라미터와 리턴값은 문자열/숫자/불리언 등의 단순한 타입만 지원합니다. - """ - name = request.name - arguments = convert_arguments_from_protobuf_to_python(request.arguments) - function = getattr(self.control, name) - result = function(*arguments) - response = KiwoomOpenApiPlusService_pb2.CallResponse() - if isinstance(result, str): - response.return_value.string_value = result - elif isinstance(result, bool): - response.return_value.bool_value = result - elif isinstance(result, int): - response.return_value.long_value = result - elif result is None: - pass - else: - raise TypeError( - "Unexpected return value type from server side dynamicCall(): %s" - % type(result) - ) - return response - - # 2. rpcs for listening and handling events - - def Listen(self, request, context): - """ - 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. - - 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. - 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. - - 서버측의 이벤트 핸들러 함수는 해당 이벤트를 클라이언트에 전송한 이후 즉시 종료됩니다. - """ - with KiwoomOpenApiPlusSomeEventHandler( - self.control, request, context - ) as handler: - for response in handler: - yield response - - def BidirectionalListen(self, request_iterator, context): - """ - 단일 혹은 복수개의 이벤트에 대해 이벤트 발생시 해당 이벤트 내용을 전달하는 RPC 입니다. - - 전달받고자 하는 이벤트 이름 목록을 요청 메시지를 통해 전달받습니다. - 이후 서버에서 목록에 포함되는 이벤트가 발생하면 해당 이벤트의 내용을 응답 메세지를 통해 전달합니다. - - 앞선 Listen() RPC 와 다르게 해당 RPC 는 이벤트 발생시 서버측에서는 이벤트 내용을 응답 메시지로 전달한 다음 - 다시 클라이언트 측에서 ACK 요청을 줄 때 까지 서버측 이벤트 핸들러 함수 내에서 대기합니다. - 따라서 클라이언트는 서버측 이벤트 핸들러 함수 컨텍스트 내에서 이벤트를 처리할 수 있고 - 처리를 완료하면 다시 서버측으로 ACK 요청을 보내 서버측 이벤트 핸들러가 완료될 수 있도록 해야 합니다. - """ - with KiwoomOpenApiPlusSomeBidirectionalEventHandler( - self.control, request_iterator, context - ) as handler: - for response in handler: - yield response - - # 3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns - - def LoginCall(self, request, context): - """ - 키움증권 서버 연결 시나리오에 해당하는 RPC 입니다. - - CommConnect() 메소드 호출 이후 발생하는 OnEventConnect() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - with KiwoomOpenApiPlusLoginEventHandler( - self.control, request, context - ) as handler: - for response in handler: - yield response - - def TransactionCall(self, request, context): - """ - TR 요청에 해당하는 RPC 입니다. - - CommRqData() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - OnReceiveTrData() 이벤트 핸들러 함수 내부에서 요청받은 TR 에 따라 관련된 데이터를 - 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. - 해당 과정에서 GetRepeatCnt() 및 GetCommData() 메소드를 내부적으로 호출합니다. - - 경우에 따라 연속조회가 필요하다면 OnReceiveTrData() 이벤트 핸들러 함수 내부에서 - 추가적인 SetInputValue() 및 CommRqData() 호출이 발생할 수 있습니다. - - 일반적인 TR 이 아닌 관심종목 관련 TR 의 경우 CommRqData() 대신 CommKwRqData() 가 - 내부적으로 호출됩니다. - - 서버측에서 CommRqData() 혹은 CommKwRqData() 호출시 내부적으로 호출제한 회피를 위한 - 대기시간이 발생할 수 있습니다. - - 최초 TR 요청 이후 특정 TR 들에서는 그와 관련된 실시간 데이터가 (OpenAPI+ 레벨에서) 자동으로 등록될 수 있습니다. - 몇몇 상황에서는 해당 실시간 데이터가 유용할 수 있으나 현재 KOAPY 에서는 별도로 사용하진 않고 있으며, - TR 에 대한 응답처리가 모두 완료된 이후에는 해당 실시간 데이터를 등록 해제하도록 처리하고 있습니다. - """ - trcode = request.transaction_code.upper() - - if trcode in ["OPTKWFID", "OPTFOFID"]: - handler = KiwoomOpenApiPlusKwTrEventHandler( - self.control, request, context, self.screen_manager - ) - else: - handler = KiwoomOpenApiPlusTrEventHandler( - self.control, request, context, self.screen_manager - ) - - with handler: - for response in handler: - yield response - - def OrderCall(self, request, context): - """ - 주문 요청에 해당하는 RPC 입니다. - - SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 및 OnReceiveChejanData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - SendOrder() 메소드 호출 이후 발생하는 OnReceiveTrData() 이벤트에서 - 주문번호가 확인 가능해야지만 정상주문으로 처리하고 그렇지 않다면 에러를 발생시킵니다. - - 일반적으로는 OnReceiveTrData() 이벤트가 먼저 발생하고 이후 OnReceiveChejanData() 이벤트가 접수/체결/잔고확인에 각각 발생합니다. - 다만 주문건수가 폭증하는 경우 OnReceiveChejan() 이벤트가 OnReceiveTrData() 이벤트보다 앞서 수신될 수 있습니다. - - 이외에 주문거부등의 케이스에서 주문거부 사유 등이 OnReceiveMsg() 이벤트로 반환됩니다. - - 기본적으로 매수/매도 주문의 경우 주문받은 수량이 모두 체결될때까지 이벤트를 처리해 전달합니다. - """ - with KiwoomOpenApiPlusOrderEventHandler( - self.control, request, context, self.screen_manager - ) as handler: - for response in handler: - yield response - - def RealCall(self, request, context): - """ - 실시간 데이터 요청에 해당하는 RPC 입니다. - - SetRealReg() 메소드 호출 이후 발생하는 OnReceiveRealData() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - - OnReceiveRealData() 이벤트 핸들러 함수 내부에서 앞서 요청받은 실시간 데이터 FID 목록 혹은 - 직접 이벤트 핸들러 함수에서 확인 가능한 FID 목록에 따라 관련된 데이터를 - 추가로 읽어 들인 뒤 알맞은 응답형태로 가공하여 클라이언트에 반환합니다. - 해당 과정에서 GetCommRealData() 메소드를 내부적으로 호출합니다. - - 해당 RPC 는 별도의 이벤트 종료 상황이 존재하지 않기 때문에 더이상 사용하지 않는 경우 - 클라이언트 측에서 해당 RPC 연결을 해제하는 식으로 더 이상 이벤트를 받지 않을 수 있습니다. - 이 경우 서버에서는 내부적으로 기 등록된 실시간 데이터에 대해 SetRealRemove() 가 호출됩니다. - """ - with KiwoomOpenApiPlusRealEventHandler( - self.control, request, context, self.screen_manager - ) as handler: - for response in handler: - yield response - - def LoadConditionCall(self, request, context): - """ - 조건검색 기능 활용 이전에 먼저 조건식 목록을 불러오는데 사용할 수 있는 RPC 입니다. - - GetConditionLoad() 메소드 호출 이후 발생하는 OnReceiveConditionVer() 이벤트를 처리하고 - 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - with KiwoomOpenApiPlusLoadConditionEventHandler( - self.control, request, context - ) as handler: - for response in handler: - yield response - - def ConditionCall(self, request, context): - """ - 조건검색 기능에 해당하는 RPC 입니다. - - SendCondition() 메소드 호출 이후 발생하는 OnReceiveTrCondition() 혹은 OnReceiveRealCondition() 이벤트를 - 처리하고 클라이언트에도 해당 이벤트 내용을 전달합니다. - """ - with KiwoomOpenApiPlusConditionEventHandler( - self.control, request, context, self.screen_manager - ) as handler: - for response in handler: - yield response - - # 4. rpcs for more complex use cases based on the previously categorized simple cases above - - def BidirectionalRealCall(self, request_iterator, context): - """ - 실시간 데이터 요청에 해당하는 RPC 입니다. - - 기존의 RealCall() RPC 는 최초 실시간 데이터 등록 이후 이벤트를 듣는 것만 가능했다면 - 새로운 BidirectionalRealCall() 에서는 최초 설정된 이벤트 스트림을 계속 유지하면서 - 신규 실시간 데이터 등록 혹은 해지를 추가로 요청해 반영할 수 있습니다. - """ - with KiwoomOpenApiPlusBidirectionalRealEventHandler( - self.control, request_iterator, context, self.screen_manager - ) as handler: - for response in handler: - yield response - - def OrderListen(self, request, context): - """ - 주문 이벤트를 듣고 싶을때 사용할 수 있는 RPC 입니다. - - 기존의 OrderCall() RPC 는 특정 주문을 수행하고 해당 주문과 관련된 이벤트들만 반환했다면 - 해당 RPC 는 특정 주문 수행 없이 모든 주문관련 이벤트를 듣고 싶을때 사용할 수 있습니다. - """ - with KiwoomOpenApiPlusAllOrderEventHandler(self.control, context) as handler: - for response in handler: - yield response - - # 5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) - - def CustomListen(self, request, context): - """ - 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. - - 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, - 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. - - 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. - """ - code = request.code - class_name = request.class_name - if code and class_name: - global_vars = {} - local_vars = {} - exec(code, global_vars, local_vars) # pylint: disable=exec-used - handler = eval(class_name, global_vars, local_vars)( - self.control, request, context - ) # pylint: disable=eval-used - assert isinstance(handler, KiwoomOpenApiPlusEventHandler) - else: - handler = KiwoomOpenApiPlusAllEventHandler(self.control, context) - with handler: - for response in handler: - yield response - - def CustomCallAndListen(self, request, context): - """ - 이벤트 처리와 관련해 특정 코드를 서버측에 실행시켜 그 로직에 따라 처리하도록 요청할 수 있습니다. - - 앞선 CustomListen() 과의 차이점은 요청시 특정 함수를 최초 1회 호출하고 이후 들어오는 이벤트를 처리한다는 점입니다. - - 해당 코드에서는 KiwoomOpenApiPlusEventHandler 클래스를 구현해야하며, - 클래스 인스턴스 생성시 control, request, context 세가지 인자를 받아 처리할 수 있어야 합니다. - - 내부적으로 exec() 및 eval() 을 사용하기 때문에 실행될 코드의 보안 및 안정성에 주의가 필요합니다. - """ - name = request.name - arguments = convert_arguments_from_protobuf_to_python(request.arguments) - function = getattr(self.control, name) - code = request.listen_request.code - class_name = request.listen_request.class_name - if code and class_name: - global_vars = {} - local_vars = {} - exec(code, global_vars, local_vars) # pylint: disable=exec-used - handler = eval(class_name, global_vars, local_vars)( - self.control, request, context - ) # pylint: disable=eval-used - assert isinstance(handler, KiwoomOpenApiPlusEventHandler) - else: - handler = KiwoomOpenApiPlusAllEventHandler(self.control, context) - with handler: - result = function(*arguments) - response = KiwoomOpenApiPlusService_pb2.CallAndListenResponse() - if isinstance(result, str): - response.call_response.return_value.string_value = result - elif isinstance(result, int): - response.call_response.return_value.long_value = result - elif result is None: - pass - else: - raise TypeError( - "Unexpected return value type from server side dynamicCall(): %s" - % type(result) - ) - yield response - for listen_response in handler: - response = KiwoomOpenApiPlusService_pb2.CallAndListenResponse() - response.listen_response = listen_response - yield response - - # 6. rpcs for other mics scenarios - - def SetLogLevel(self, request, context): - """ - 서버에 존재하는 특정 로거의 로그레벨을 설정합니다. - """ - level = request.level - logger = request.logger - logging.getLogger(logger).setLevel(level) - response = KiwoomOpenApiPlusService_pb2.SetLogLevelResponse() - return response diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.py deleted file mode 100644 index 7d3a1006..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2.py +++ /dev/null @@ -1,98 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\nFkoapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto\x12\'koapy.backend.kiwoom_open_api_plus.grpc\"W\n\x08\x41rgument\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x14\n\nlong_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"a\n\x0b\x43\x61llRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\targuments\x18\x02 \x03(\x0b\x32\x31.koapy.backend.kiwoom_open_api_plus.grpc.Argument\"Z\n\x0bReturnValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x14\n\nlong_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x03 \x01(\x08H\x00\x42\x07\n\x05value\"Z\n\x0c\x43\x61llResponse\x12J\n\x0creturn_value\x18\x01 \x01(\x0b\x32\x34.koapy.backend.kiwoom_open_api_plus.grpc.ReturnValue\"L\n\rListenRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05slots\x18\x02 \x03(\t\x12\x0c\n\x04\x63ode\x18\x03 \x01(\t\x12\x12\n\nclass_name\x18\x04 \x01(\t\"\x1e\n\x0eHandledRequest\x12\x0c\n\x04time\x18\x01 \x01(\x02\"!\n\x11StopListenRequest\x12\x0c\n\x04time\x18\x01 \x01(\x02\"\xa8\x02\n\x1a\x42idirectionalListenRequest\x12P\n\x0elisten_request\x18\x01 \x01(\x0b\x32\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequestH\x00\x12R\n\x0fhandled_request\x18\x02 \x01(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.HandledRequestH\x00\x12Y\n\x13stop_listen_request\x18\x03 \x01(\x0b\x32:.koapy.backend.kiwoom_open_api_plus.grpc.StopListenRequestH\x00\x42\t\n\x07request\"+\n\nSingleData\x12\r\n\x05names\x18\x01 \x03(\t\x12\x0e\n\x06values\x18\x02 \x03(\t\" \n\x0eRepeatedString\x12\x0e\n\x06values\x18\x01 \x03(\t\"c\n\tMultiData\x12\r\n\x05names\x18\x01 \x03(\t\x12G\n\x06values\x18\x02 \x03(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.RepeatedString\"\xf6\x01\n\x0eListenResponse\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x44\n\targuments\x18\x02 \x03(\x0b\x32\x31.koapy.backend.kiwoom_open_api_plus.grpc.Argument\x12H\n\x0bsingle_data\x18\x03 \x01(\x0b\x32\x33.koapy.backend.kiwoom_open_api_plus.grpc.SingleData\x12\x46\n\nmulti_data\x18\x04 \x01(\x0b\x32\x32.koapy.backend.kiwoom_open_api_plus.grpc.MultiData\"\xb2\x01\n\x14\x43\x61llAndListenRequest\x12J\n\x0c\x63\x61ll_request\x18\x01 \x01(\x0b\x32\x34.koapy.backend.kiwoom_open_api_plus.grpc.CallRequest\x12N\n\x0elisten_request\x18\x02 \x01(\x0b\x32\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\"\xc7\x01\n\x15\x43\x61llAndListenResponse\x12N\n\rcall_response\x18\x01 \x01(\x0b\x32\x35.koapy.backend.kiwoom_open_api_plus.grpc.CallResponseH\x00\x12R\n\x0flisten_response\x18\x02 \x01(\x0b\x32\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponseH\x00\x42\n\n\x08response\"\x8d\x02\n\x10LoginCredentials\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x15\n\ruser_password\x18\x02 \x01(\t\x12\x15\n\rcert_password\x18\x03 \x01(\t\x12\x15\n\ris_simulation\x18\x04 \x01(\x08\x12j\n\x11\x61\x63\x63ount_passwords\x18\x05 \x03(\x0b\x32O.koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials.AccountPasswordsEntry\x1a\x37\n\x15\x41\x63\x63ountPasswordsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"^\n\x0cLoginRequest\x12N\n\x0b\x63redentials\x18\x01 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.LoginCredentials\"R\n\x10RealRequestFlags\x12\x12\n\ninfer_fids\x18\x01 \x01(\x08\x12\x16\n\x0ereadable_names\x18\x02 \x01(\x08\x12\x12\n\nfast_parse\x18\x03 \x01(\x08\"\xa1\x01\n\x0bRealRequest\x12\x11\n\tscreen_no\x18\x01 \x03(\t\x12\x11\n\tcode_list\x18\x02 \x03(\t\x12\x10\n\x08\x66id_list\x18\x03 \x03(\x05\x12\x10\n\x08opt_type\x18\x04 \x01(\t\x12H\n\x05\x66lags\x18\x05 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\"\x97\x01\n\x18TransactionStopCondition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12^\n\ncomparator\x18\x03 \x01(\x0e\x32J.koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopConditionCompartor\"\x84\x03\n\x12TransactionRequest\x12\x14\n\x0crequest_name\x18\x01 \x01(\t\x12\x18\n\x10transaction_code\x18\x02 \x01(\t\x12\x11\n\tscreen_no\x18\x03 \x01(\t\x12W\n\x06inputs\x18\x04 \x03(\x0b\x32G.koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest.InputsEntry\x12Y\n\x0estop_condition\x18\x05 \x01(\x0b\x32\x41.koapy.backend.kiwoom_open_api_plus.grpc.TransactionStopCondition\x12H\n\x05\x66lags\x18\x06 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\x1a-\n\x0bInputsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"]\n\x17OrderSubscriptionTarget\x12\x0b\n\x03RET\x18\x01 \x01(\x08\x12\n\n\x02TR\x18\x02 \x01(\x08\x12\x0c\n\x04REAL\x18\x03 \x01(\x08\x12\x0b\n\x03MSG\x18\x04 \x01(\x08\x12\x0e\n\x06\x43HEJAN\x18\x05 \x01(\x08\"\x8f\x02\n\x0cOrderRequest\x12\x14\n\x0crequest_name\x18\x01 \x01(\t\x12\x11\n\tscreen_no\x18\x02 \x01(\t\x12\x12\n\naccount_no\x18\x03 \x01(\t\x12\x12\n\norder_type\x18\x04 \x01(\x03\x12\x0c\n\x04\x63ode\x18\x05 \x01(\t\x12\x10\n\x08quantity\x18\x06 \x01(\x03\x12\r\n\x05price\x18\x07 \x01(\x03\x12\x12\n\nquote_type\x18\x08 \x01(\t\x12\x19\n\x11original_order_no\x18\t \x01(\t\x12P\n\x06target\x18\n \x01(\x0b\x32@.koapy.backend.kiwoom_open_api_plus.grpc.OrderSubscriptionTarget\"\x16\n\x14LoadConditionRequest\"D\n\x15\x43onditionRequestFlags\x12\x11\n\twith_info\x18\x01 \x01(\x08\x12\x18\n\x10is_future_option\x18\x02 \x01(\x08\"\xd0\x01\n\x10\x43onditionRequest\x12\x11\n\tscreen_no\x18\x01 \x01(\t\x12\x16\n\x0e\x63ondition_name\x18\x02 \x01(\t\x12\x17\n\x0f\x63ondition_index\x18\x03 \x01(\x05\x12\x13\n\x0bsearch_type\x18\x04 \x01(\x05\x12\x14\n\x0crequest_name\x18\x05 \x01(\t\x12M\n\x05\x66lags\x18\x06 \x01(\x0b\x32>.koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequestFlags\"3\n\x12SetLogLevelRequest\x12\r\n\x05level\x18\x01 \x01(\x05\x12\x0e\n\x06logger\x18\x02 \x01(\t\"\x15\n\x13SetLogLevelResponse\"\x80\x01\n\"BidirectionalRealInitializeRequest\x12\x10\n\x08\x66id_list\x18\x01 \x03(\x05\x12H\n\x05\x66lags\x18\x02 \x01(\x0b\x32\x39.koapy.backend.kiwoom_open_api_plus.grpc.RealRequestFlags\"G\n BidirectionalRealRegisterRequest\x12\x11\n\tcode_list\x18\x01 \x03(\t\x12\x10\n\x08\x66id_list\x18\x02 \x03(\x05\"3\n\x1e\x42idirectionalRealRemoveRequest\x12\x11\n\tcode_list\x18\x01 \x03(\t\"\x1e\n\x1c\x42idirectionalRealStopRequest\"\xb9\x03\n\x18\x42idirectionalRealRequest\x12i\n\x12initialize_request\x18\x01 \x01(\x0b\x32K.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealInitializeRequestH\x00\x12\x65\n\x10register_request\x18\x02 \x01(\x0b\x32I.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRegisterRequestH\x00\x12\x61\n\x0eremove_request\x18\x03 \x01(\x0b\x32G.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRemoveRequestH\x00\x12]\n\x0cstop_request\x18\x04 \x01(\x0b\x32\x45.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealStopRequestH\x00\x42\t\n\x07request*\x9d\x01\n!TransactionStopConditionCompartor\x12\x19\n\x15LESS_THAN_OR_EQUAL_TO\x10\x00\x12\r\n\tLESS_THAN\x10\x01\x12\x1c\n\x18GREATER_THAN_OR_EQUAL_TO\x10\x02\x12\x10\n\x0cGREATER_THAN\x10\x03\x12\x0c\n\x08\x45QUAL_TO\x10\x04\x12\x10\n\x0cNOT_EQUAL_TO\x10\x05\x32\xa6\x0f\n\x18KiwoomOpenApiPlusService\x12u\n\x04\x43\x61ll\x12\x34.koapy.backend.kiwoom_open_api_plus.grpc.CallRequest\x1a\x35.koapy.backend.kiwoom_open_api_plus.grpc.CallResponse\"\x00\x12}\n\x06Listen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x99\x01\n\x13\x42idirectionalListen\x12\x43.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00(\x01\x30\x01\x12\x7f\n\tLoginCall\x12\x35.koapy.backend.kiwoom_open_api_plus.grpc.LoginRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x8b\x01\n\x0fTransactionCall\x12;.koapy.backend.kiwoom_open_api_plus.grpc.TransactionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x7f\n\tOrderCall\x12\x35.koapy.backend.kiwoom_open_api_plus.grpc.OrderRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12}\n\x08RealCall\x12\x34.koapy.backend.kiwoom_open_api_plus.grpc.RealRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x8f\x01\n\x11LoadConditionCall\x12=.koapy.backend.kiwoom_open_api_plus.grpc.LoadConditionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x87\x01\n\rConditionCall\x12\x39.koapy.backend.kiwoom_open_api_plus.grpc.ConditionRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x99\x01\n\x15\x42idirectionalRealCall\x12\x41.koapy.backend.kiwoom_open_api_plus.grpc.BidirectionalRealRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00(\x01\x30\x01\x12\x82\x01\n\x0bOrderListen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x83\x01\n\x0c\x43ustomListen\x12\x36.koapy.backend.kiwoom_open_api_plus.grpc.ListenRequest\x1a\x37.koapy.backend.kiwoom_open_api_plus.grpc.ListenResponse\"\x00\x30\x01\x12\x98\x01\n\x13\x43ustomCallAndListen\x12=.koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenRequest\x1a>.koapy.backend.kiwoom_open_api_plus.grpc.CallAndListenResponse\"\x00\x30\x01\x12\x8a\x01\n\x0bSetLogLevel\x12;.koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelRequest\x1a<.koapy.backend.kiwoom_open_api_plus.grpc.SetLogLevelResponse\"\x00\x62\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY._options = None - _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY._serialized_options = b'8\001' - _TRANSACTIONREQUEST_INPUTSENTRY._options = None - _TRANSACTIONREQUEST_INPUTSENTRY._serialized_options = b'8\001' - _TRANSACTIONSTOPCONDITIONCOMPARTOR._serialized_start=4388 - _TRANSACTIONSTOPCONDITIONCOMPARTOR._serialized_end=4545 - _ARGUMENT._serialized_start=115 - _ARGUMENT._serialized_end=202 - _CALLREQUEST._serialized_start=204 - _CALLREQUEST._serialized_end=301 - _RETURNVALUE._serialized_start=303 - _RETURNVALUE._serialized_end=393 - _CALLRESPONSE._serialized_start=395 - _CALLRESPONSE._serialized_end=485 - _LISTENREQUEST._serialized_start=487 - _LISTENREQUEST._serialized_end=563 - _HANDLEDREQUEST._serialized_start=565 - _HANDLEDREQUEST._serialized_end=595 - _STOPLISTENREQUEST._serialized_start=597 - _STOPLISTENREQUEST._serialized_end=630 - _BIDIRECTIONALLISTENREQUEST._serialized_start=633 - _BIDIRECTIONALLISTENREQUEST._serialized_end=929 - _SINGLEDATA._serialized_start=931 - _SINGLEDATA._serialized_end=974 - _REPEATEDSTRING._serialized_start=976 - _REPEATEDSTRING._serialized_end=1008 - _MULTIDATA._serialized_start=1010 - _MULTIDATA._serialized_end=1109 - _LISTENRESPONSE._serialized_start=1112 - _LISTENRESPONSE._serialized_end=1358 - _CALLANDLISTENREQUEST._serialized_start=1361 - _CALLANDLISTENREQUEST._serialized_end=1539 - _CALLANDLISTENRESPONSE._serialized_start=1542 - _CALLANDLISTENRESPONSE._serialized_end=1741 - _LOGINCREDENTIALS._serialized_start=1744 - _LOGINCREDENTIALS._serialized_end=2013 - _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY._serialized_start=1958 - _LOGINCREDENTIALS_ACCOUNTPASSWORDSENTRY._serialized_end=2013 - _LOGINREQUEST._serialized_start=2015 - _LOGINREQUEST._serialized_end=2109 - _REALREQUESTFLAGS._serialized_start=2111 - _REALREQUESTFLAGS._serialized_end=2193 - _REALREQUEST._serialized_start=2196 - _REALREQUEST._serialized_end=2357 - _TRANSACTIONSTOPCONDITION._serialized_start=2360 - _TRANSACTIONSTOPCONDITION._serialized_end=2511 - _TRANSACTIONREQUEST._serialized_start=2514 - _TRANSACTIONREQUEST._serialized_end=2902 - _TRANSACTIONREQUEST_INPUTSENTRY._serialized_start=2857 - _TRANSACTIONREQUEST_INPUTSENTRY._serialized_end=2902 - _ORDERSUBSCRIPTIONTARGET._serialized_start=2904 - _ORDERSUBSCRIPTIONTARGET._serialized_end=2997 - _ORDERREQUEST._serialized_start=3000 - _ORDERREQUEST._serialized_end=3271 - _LOADCONDITIONREQUEST._serialized_start=3273 - _LOADCONDITIONREQUEST._serialized_end=3295 - _CONDITIONREQUESTFLAGS._serialized_start=3297 - _CONDITIONREQUESTFLAGS._serialized_end=3365 - _CONDITIONREQUEST._serialized_start=3368 - _CONDITIONREQUEST._serialized_end=3576 - _SETLOGLEVELREQUEST._serialized_start=3578 - _SETLOGLEVELREQUEST._serialized_end=3629 - _SETLOGLEVELRESPONSE._serialized_start=3631 - _SETLOGLEVELRESPONSE._serialized_end=3652 - _BIDIRECTIONALREALINITIALIZEREQUEST._serialized_start=3655 - _BIDIRECTIONALREALINITIALIZEREQUEST._serialized_end=3783 - _BIDIRECTIONALREALREGISTERREQUEST._serialized_start=3785 - _BIDIRECTIONALREALREGISTERREQUEST._serialized_end=3856 - _BIDIRECTIONALREALREMOVEREQUEST._serialized_start=3858 - _BIDIRECTIONALREALREMOVEREQUEST._serialized_end=3909 - _BIDIRECTIONALREALSTOPREQUEST._serialized_start=3911 - _BIDIRECTIONALREALSTOPREQUEST._serialized_end=3941 - _BIDIRECTIONALREALREQUEST._serialized_start=3944 - _BIDIRECTIONALREALREQUEST._serialized_end=4385 - _KIWOOMOPENAPIPLUSSERVICE._serialized_start=4548 - _KIWOOMOPENAPIPLUSSERVICE._serialized_end=6506 -# @@protoc_insertion_point(module_scope) diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.py b/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.py deleted file mode 100644 index 2c0e6616..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc.py +++ /dev/null @@ -1,548 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 as koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2 - - -class KiwoomOpenApiPlusServiceStub: - """Missing associated documentation comment in .proto file.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.Call = channel.unary_unary( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Call', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.FromString, - ) - self.Listen = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Listen', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.BidirectionalListen = channel.stream_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalListen', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.LoginCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoginCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.TransactionCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/TransactionCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.OrderCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.RealCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/RealCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.LoadConditionCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoadConditionCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.ConditionCall = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/ConditionCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.BidirectionalRealCall = channel.stream_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalRealCall', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.OrderListen = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderListen', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.CustomListen = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomListen', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - ) - self.CustomCallAndListen = channel.unary_stream( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomCallAndListen', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.FromString, - ) - self.SetLogLevel = channel.unary_unary( - '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/SetLogLevel', - request_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.SerializeToString, - response_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.FromString, - ) - - -class KiwoomOpenApiPlusServiceServicer: - """Missing associated documentation comment in .proto file.""" - - def Call(self, request, context): - """1. rpcs for general function calls - - unary rpc for an arbitrary function call, - can invoke arbitrary function on the server side by giving its name and arguments, - currently only simple data types like str and int are supported for arguments and return values - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def Listen(self, request, context): - """2. rpcs for listening and handling events - - server streaming rpc usually for listening events, - server will simply send stream items to client whenever event that is being listened is triggered, - client can handle those events solely on its own on client side but there is no guarantee that it will be synced with the server, - which means that event handler on the server side will not wait for the client to finish handling each event - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def BidirectionalListen(self, request_iterator, context): - """bidirectional streaming rpc usually for listening and handling events with proper callbacks, - server will send an stream item to client whenever an event is triggered and will wait for an client's ack, - so that following callbacks from the client can actually be processed inside the server's event handler context - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def LoginCall(self, request, context): - """3. rpcs for simple use cases that can be categorized into serveral distinct usage patterns - - server streaming rpc for login/connect scenario, - would invoke CommConnect() and wait for OnEventConnect() event to test its success - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def TransactionCall(self, request, context): - """server streaming rpc for general transaction requests, - would invoke CommRqData() with several SetInputValue()s for a transaction request, - would wait for OnReceiveTrData() events, - would handle those events to gather results by invoking GetRepeatCnt() and GetCommData() inside, - might do additional CommRqData() and SetInputValue() inside event handler for possible consecutive lookups - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def OrderCall(self, request, context): - """server streaming rpc for making orders (buy/sell + update/cancel), - would invoke SendOrder() for submitting an order, - would wait for OnReceiveTrData() and OnReceiveChejanData() events to track its progress - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def RealCall(self, request, context): - """server streaming rpc for listening realtime data events, - certain transaction requests would also register some realtime data to be sent, - but usually would just call SetRealReg() to register desired realtime data to listen explicitly, - and would call SetRealRemove() to unregister them after done using, - would wait for OnReceiveRealData() events - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def LoadConditionCall(self, request, context): - """server streaming rpc for loading condition settings for conditioned search, - would call GetConditionLoad() and wait for OnReceiveConditionVer() event to test its success - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def ConditionCall(self, request, context): - """server streaming rpc for conditioned search (serching stocks with serveral conditions), - would call SendCondition() and wait for OnReceiveTrCondition() or OnReceiveRealCondition() based on its requested type - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def BidirectionalRealCall(self, request_iterator, context): - """4. rpcs for more complex use cases based on the previously categorized simple cases above - - bidirectional streaming rpc for listening realtime data events, - with capability of managing observation pool (what stocks, what fields to listen to) online, - those management requests would be sent over the client streaming line, - and ordinary realtime data events would be sent over the server streaming line - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def OrderListen(self, request, context): - """server streaming rpc for just listening order events (without submiting any order request compared to the simple case), - this is one-sided streaming rpc (server streaming rpc) like Listen() rpc, - so server would just send stream items with no consideration on coordination with its client - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def CustomListen(self, request, context): - """5. rpcs for customized usage scenario (when there is no proper predefined interface to utilize) - - pretty much similar to server streaming Listen() rpc, - but event handler would be instantiated dynamically based on the code given through the request - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def CustomCallAndListen(self, request, context): - """pretty much similar to server streaming XXXCall() rpcs (or even Call() rpc), - but event handler would be instantiated dynamically based on the code given through the request - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def SetLogLevel(self, request, context): - """6. rpcs for other mics scenarios - - would update log level of process that this grpc server lives - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_KiwoomOpenApiPlusServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'Call': grpc.unary_unary_rpc_method_handler( - servicer.Call, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.SerializeToString, - ), - 'Listen': grpc.unary_stream_rpc_method_handler( - servicer.Listen, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'BidirectionalListen': grpc.stream_stream_rpc_method_handler( - servicer.BidirectionalListen, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'LoginCall': grpc.unary_stream_rpc_method_handler( - servicer.LoginCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'TransactionCall': grpc.unary_stream_rpc_method_handler( - servicer.TransactionCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'OrderCall': grpc.unary_stream_rpc_method_handler( - servicer.OrderCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'RealCall': grpc.unary_stream_rpc_method_handler( - servicer.RealCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'LoadConditionCall': grpc.unary_stream_rpc_method_handler( - servicer.LoadConditionCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'ConditionCall': grpc.unary_stream_rpc_method_handler( - servicer.ConditionCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'BidirectionalRealCall': grpc.stream_stream_rpc_method_handler( - servicer.BidirectionalRealCall, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'OrderListen': grpc.unary_stream_rpc_method_handler( - servicer.OrderListen, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'CustomListen': grpc.unary_stream_rpc_method_handler( - servicer.CustomListen, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.SerializeToString, - ), - 'CustomCallAndListen': grpc.unary_stream_rpc_method_handler( - servicer.CustomCallAndListen, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.SerializeToString, - ), - 'SetLogLevel': grpc.unary_unary_rpc_method_handler( - servicer.SetLogLevel, - request_deserializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.FromString, - response_serializer=koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) - - - # This class is part of an EXPERIMENTAL API. -class KiwoomOpenApiPlusService: - """Missing associated documentation comment in .proto file.""" - - @staticmethod - def Call(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Call', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def Listen(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/Listen', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def BidirectionalListen(request_iterator, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.stream_stream(request_iterator, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalListen', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalListenRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def LoginCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoginCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoginRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def TransactionCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/TransactionCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.TransactionRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def OrderCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.OrderRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def RealCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/RealCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.RealRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def LoadConditionCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/LoadConditionCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.LoadConditionRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def ConditionCall(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/ConditionCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ConditionRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def BidirectionalRealCall(request_iterator, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.stream_stream(request_iterator, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/BidirectionalRealCall', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.BidirectionalRealRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def OrderListen(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/OrderListen', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def CustomListen(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomListen', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.ListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def CustomCallAndListen(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_stream(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/CustomCallAndListen', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.CallAndListenResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def SetLogLevel(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService/SetLogLevel', - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelRequest.SerializeToString, - koapy_dot_backend_dot_kiwoom__open__api__plus_dot_grpc_dot_KiwoomOpenApiPlusService__pb2.SetLogLevelResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/__init__.py b/koapy/backend/kiwoom_open_api_plus/grpc/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.py deleted file mode 100644 index a79f2963..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler.py +++ /dev/null @@ -1,239 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.backend.kiwoom_open_api_plus.utils.list_conversion import string_to_list -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusConditionEventHandler( - KiwoomOpenApiPlusEventHandlerForGrpc, Logging -): - def __init__(self, control, request, context, screen_manager): - super().__init__(control, context) - self._request = request - self._screen_manager = screen_manager - - self._screen_no = request.screen_no - self._condition_name = request.condition_name - self._condition_index = request.condition_index - self._search_type = request.search_type - - self._request_name = request.request_name or "관심종목정보요청" - self._with_info = request.flags.with_info - self._is_future_option = request.flags.is_future_option - self._type_flag = 3 if self._is_future_option else 0 - - self._trcode = {0: "OPTKWFID", 3: "OPTFOFID"}[self._type_flag] - self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) - - if self._trinfo is None: - self.logger.error("Cannot find names for trcode %s", self._trinfo) - - self._single_names = self._trinfo.get_single_output_names() - self._multi_names = self._trinfo.get_multi_output_names() - - def on_enter(self): - self.control.EnsureConditionLoaded() - condition_names = self.control.GetConditionNameListAsList() - assert (self._condition_index, self._condition_name) in condition_names - self._screen_no = self._screen_manager.borrow_screen(self._screen_no) - self.add_callback(self._screen_manager.return_screen, self._screen_no) - self.add_callback(self.control.DisconnectRealData, self._screen_no) - self.add_callback( - self.control.SendConditionStop, - self._screen_no, - self._condition_name, - self._condition_index, - ) - KiwoomOpenApiPlusError.try_or_raise_boolean( - self.control.RateLimitedSendCondition.queuedCall( - self._screen_no, - self._condition_name, - self._condition_index, - self._search_type, - ), - "Failed to send condition", - except_callback=self.observer.on_error, - ) - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - if (scrnno, condition_name, condition_index) == ( - self._screen_no, - self._condition_name, - self._condition_index, - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrCondition" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = codelist - response.arguments.add().string_value = condition_name - response.arguments.add().long_value = condition_index - response.arguments.add().long_value = prevnext - - self.observer.on_next(response) - - if self._with_info: - if "^" in codelist: - items = string_to_list(codelist, sep=";") - items = [string_to_list(item, sep="^") for item in items] - items = [tuple(item) for item in items] - codes = [item[0] for item in items] - else: - codes = string_to_list(codelist, sep=";") - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommKwRqData.queuedCall( - codelist, - 0, - len(codes), - self._type_flag, - self._request_name, - self._screen_no, - ), - except_callback=self.observer.on_error, - ) - - should_continue = str(prevnext) not in ["", "0"] - should_not_complete = ( - self._search_type == 1 or self._with_info or should_continue - ) - should_complete = not should_not_complete - - if should_complete: - self.observer.on_completed() - return - elif should_continue: - try: - raise KiwoomOpenApiPlusError("Should not reach here") - # pylint: disable=unreachable - self.control.RateLimitedSendCondition.queuedCall( - self._screen_no, - self._condition_name, - self._condition_index, - int(prevnext), - ) - except KiwoomOpenApiPlusError as e: - self.observer.on_error(e) - return - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - if (condition_name, int(condition_index)) == ( - self._condition_name, - self._condition_index, - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealCondition" - response.arguments.add().string_value = code - response.arguments.add().string_value = condition_type - response.arguments.add().string_value = condition_name - response.arguments.add().string_value = condition_index - - self.observer.on_next(response) - - if self._with_info: - codelist = code - codes = [code] - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommKwRqData.queuedCall( - codelist, - 0, - len(codes), - self._type_flag, - self._request_name, - self._screen_no, - ), - except_callback=self.observer.on_error, - ) - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - if (scrnno, rqname) == (self._screen_no, self._request_name): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - - should_continue = str(prevnext) not in ["", "0"] - should_not_complete = self._search_type == 1 or should_continue - should_complete = not should_not_complete - - repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) - - assert trcode.upper() == self._trcode - - if repeat_cnt > 0: - if len(self._multi_names) == 0: - self.logger.warning( - "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" - ) - multi_names = self._multi_names - self._multi_names = self._single_names - self._single_names = multi_names - if len(self._multi_names) > 0: - rows = [ - [ - self.control.GetCommData( - trcode, recordname, i, name - ).strip() - for name in self._multi_names - ] - for i in range(repeat_cnt) - ] - response.multi_data.names.extend(self._multi_names) - for row in rows: - response.multi_data.values.add().values.extend(row) - - if len(self._single_names) > 0: - values = [ - self.control.GetCommData(trcode, recordname, 0, name).strip() - for name in self._single_names - ] - response.single_data.names.extend(self._single_names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - if should_complete: - self.observer.on_completed() - return - elif should_continue: - try: - raise KiwoomOpenApiPlusError("Should not reach here") - # pylint: disable=unreachable - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommKwRqData.queuedCall( - self._codelist, - int(prevnext), - len(self._codes), - 3 if self._is_future_option else 0, - self._request_name, - self._screen_no, - ), - except_callback=self.observer.on_error, - ) - except KiwoomOpenApiPlusError as e: - self.observer.on_error(e) - return diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.py deleted file mode 100644 index f578ebe3..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc.py +++ /dev/null @@ -1,15 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import ( - KiwoomOpenApiPlusEventHandler, -) - - -class KiwoomOpenApiPlusEventHandlerForGrpc(KiwoomOpenApiPlusEventHandler): - def __init__(self, control, context): - super().__init__(control) - - self._context = context - self._context.add_callback(self.stop) - - @property - def context(self): - return self._context diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.py deleted file mode 100644 index 5b76c3d6..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers.py +++ /dev/null @@ -1,372 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.utils.logging.Logging import Logging -from koapy.utils.notimplemented import isimplemented - - -class KiwoomOpenApiPlusLazyAllEventHandler( - KiwoomOpenApiPlusEventHandlerForGrpc, Logging -): - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - self.observer.on_next(response) - - def OnReceiveRealData(self, code, realtype, realdata): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealData" - response.arguments.add().string_value = code - response.arguments.add().string_value = realtype - response.arguments.add().string_value = realdata - self.observer.on_next(response) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveMsg" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = msg - self.observer.on_next(response) - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveChejanData" - response.arguments.add().string_value = gubun - response.arguments.add().long_value = itemcnt - response.arguments.add().string_value = fidlist - self.observer.on_next(response) - - def OnEventConnect(self, errcode): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnEventConnect" - response.arguments.add().long_value = errcode - self.observer.on_next(response) - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealCondition" - response.arguments.add().string_value = code - response.arguments.add().string_value = condition_type - response.arguments.add().string_value = condition_name - response.arguments.add().string_value = condition_index - self.observer.on_next(response) - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrCondition" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = codelist - response.arguments.add().string_value = condition_name - response.arguments.add().long_value = condition_index - response.arguments.add().long_value = prevnext - self.observer.on_next(response) - - def OnReceiveConditionVer(self, ret, msg): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveConditionVer" - response.arguments.add().long_value = ret - response.arguments.add().string_value = msg - self.observer.on_next(response) - - -class KiwoomOpenApiPlusEagerAllEventHandler( - KiwoomOpenApiPlusEventHandlerForGrpc, Logging -): - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - - repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) - - trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(trcode) - - if trinfo is None: - self.logger.error("Cannot find names for trcode %s", trinfo) - - single_names = trinfo.get_single_output_names() - multi_names = trinfo.get_multi_output_names() - - if len(single_names) > 0: - values = [ - self.control.GetCommData(trcode, recordname, 0, name).strip() - for name in single_names - ] - response.single_data.names.extend(single_names) - response.single_data.values.extend(values) - - if repeat_cnt > 0 and len(multi_names) > 0: - rows = [ - [ - self.control.GetCommData(trcode, recordname, i, name).strip() - for name in multi_names - ] - for i in range(repeat_cnt) - ] - response.multi_data.names.extend(multi_names) - for row in rows: - response.multi_data.values.add().values.extend(row) - - self.observer.on_next(response) - - def OnReceiveRealData(self, code, realtype, realdata): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealData" - response.arguments.add().string_value = code - response.arguments.add().string_value = realtype - response.arguments.add().string_value = realdata - - fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) - - if fids is None: - self.logger.error("Cannot find fids for realtype %s", realtype) - - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids - ] - values = [self.control.GetCommRealData(code, fid) for fid in fids] - - assert len(names) == len(values) - - response.single_data.names.extend(names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveMsg" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = msg - self.observer.on_next(response) - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveChejanData" - response.arguments.add().string_value = gubun - response.arguments.add().long_value = itemcnt - response.arguments.add().string_value = fidlist - - fids = fidlist.rstrip(";") - fids = fids.split(";") if fids else [] - fids = [int(fid) for fid in fids] - - assert itemcnt == len(fids) - - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids - ] - values = [self.control.GetChejanData(fid).strip() for fid in fids] - - response.single_data.names.extend(names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - def OnEventConnect(self, errcode): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnEventConnect" - response.arguments.add().long_value = errcode - self.observer.on_next(response) - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealCondition" - response.arguments.add().string_value = code - response.arguments.add().string_value = condition_type - response.arguments.add().string_value = condition_name - response.arguments.add().string_value = condition_index - self.observer.on_next(response) - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrCondition" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = codelist - response.arguments.add().string_value = condition_name - response.arguments.add().long_value = condition_index - response.arguments.add().long_value = prevnext - self.observer.on_next(response) - - def OnReceiveConditionVer(self, ret, msg): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveConditionVer" - response.arguments.add().long_value = ret - response.arguments.add().string_value = msg - self.observer.on_next(response) - - -class KiwoomOpenApiPlusAllEventHandler(KiwoomOpenApiPlusEagerAllEventHandler): - - pass - - -class KiwoomOpenApiPlusLazySomeEventHandler(KiwoomOpenApiPlusLazyAllEventHandler): - def __init__(self, control, request, context): - super().__init__(control, context) - self._request = request - - def slots(self): - names = self.names() - slots = [getattr(self, name) for name in names] - names_and_slots_implemented = [ - (name, slot) - for name, slot in zip(names, slots) - if isimplemented(slot) and name in self._request.slots - ] - return names_and_slots_implemented - - -class KiwoomOpenApiPlusEagerSomeEventHandler(KiwoomOpenApiPlusEagerAllEventHandler): - def __init__(self, control, request, context): - super().__init__(control, context) - self._request = request - - def slots(self): - names = self.names() - slots = [getattr(self, name) for name in names] - names_and_slots_implemented = [ - (name, slot) - for name, slot in zip(names, slots) - if isimplemented(slot) and name in self._request.slots - ] - return names_and_slots_implemented - - -class KiwoomOpenApiPlusSomeEventHandler(KiwoomOpenApiPlusEagerSomeEventHandler): - - pass - - -class KiwoomOpenApiPlusSomeBidirectionalEventHandler( - KiwoomOpenApiPlusLazySomeEventHandler -): - def __init__(self, control, request_iterator, context): - self._request_iterator = request_iterator - self._first_request = next(self._request_iterator) - assert self._first_request.HasField("listen_request") - self._request = request = self._first_request.listen_request - super().__init__(control, request, context) - - def await_handled(self): - request = next(self._request_iterator) - if request.HasField("handled_request"): - pass - elif request.HasField("stop_listen_request"): - self.observer.on_completed() - else: - raise KiwoomOpenApiPlusError("Unexpected request") - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - super().OnReceiveTrData( - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ) - self.await_handled() - - def OnReceiveRealData(self, code, realtype, realdata): - super().OnReceiveRealData(code, realtype, realdata) - self.await_handled() - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - super().OnReceiveMsg(scrnno, rqname, trcode, msg) - self.await_handled() - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - super().OnReceiveChejanData(gubun, itemcnt, fidlist) - self.await_handled() - - def OnEventConnect(self, errcode): - super().OnEventConnect(errcode) - self.await_handled() - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - super().OnReceiveRealCondition( - code, condition_type, condition_name, condition_index - ) - self.await_handled() - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - super().OnReceiveTrCondition( - scrnno, codelist, condition_name, condition_index, prevnext - ) - self.await_handled() - - def OnReceiveConditionVer(self, ret, msg): - super().OnReceiveConditionVer(ret, msg) - self.await_handled() diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.py deleted file mode 100644 index 1d67f226..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler.py +++ /dev/null @@ -1,192 +0,0 @@ -import operator -import re - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.utils.itertools import chunk -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusKwTrEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): - - _num_codes_per_request = 100 - - def __init__(self, control, request, context, screen_manager): - super().__init__(control, context) - self._request = request - self._screen_manager = screen_manager - - self._rqname = request.request_name - self._trcode = request.transaction_code.upper() - self._scrnno = request.screen_no - self._inputs = request.inputs - - assert self._trcode in ["OPTKWFID", "OPTFOFID"] - - self._type_flag = {"OPTKWFID": 0, "OPTFOFID": 3}[self._trcode] - - self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) - - if self._trinfo is None: - self.logger.error("Cannot find names for trcode %s", self._trinfo) - - self._input_code = self._inputs.get("종목코드") - - self._code_list = self._input_code.rstrip(";").split(";") - self._code_lists = [ - codes for codes in chunk(self._code_list, self._num_codes_per_request) - ] - self._scrnnos = [None for _ in range(len(self._code_lists))] - self._scrnnos[0] = self._scrnno - self._scrnnos_completed = {} - - self._single_names = self._trinfo.get_single_output_names() - self._multi_names = self._trinfo.get_multi_output_names() - - stop_condition = request.stop_condition - stop_condition_is_valid = all( - [ - stop_condition is not None, - stop_condition.name is not None, - len(stop_condition.name) > 0, - stop_condition.name in self._multi_names, - ] - ) - - if stop_condition_is_valid: - column_index_to_check = self._multi_names.index(stop_condition.name) - comparator = { - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO: operator.le, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN: operator.lt, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO: operator.ge, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN: operator.gt, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO: operator.eq, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO: operator.ne, - }.get(stop_condition.comparator, operator.le) - - def is_stop_condition(row): - return comparator(row[column_index_to_check], stop_condition.value) - - else: - - def is_stop_condition(_): - return False - - self._is_stop_condition = is_stop_condition - - def on_enter(self): - for i, scrnno in enumerate(self._scrnnos): - scrnno = self._screen_manager.borrow_screen(scrnno) - self._scrnnos[i] = scrnno - self._scrnnos_completed[scrnno] = False - for codes, scrnno in zip(self._code_lists, self._scrnnos): - self.add_callback(self._screen_manager.return_screen, scrnno) - self.add_callback(self.control.DisconnectRealData, scrnno) - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommKwRqData.queuedCall( - ";".join(codes), - 0, - len(codes), - self._type_flag, - self._rqname, - scrnno, - ), - except_callback=self.observer.on_error, - ) - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - if (rqname, trcode) == (self._rqname, self._trcode) and scrnno in self._scrnnos: - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - - should_stop = prevnext in ["", "0"] - repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) - - if repeat_cnt > 0: - if len(self._multi_names) == 0: - self.logger.warning( - "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" - ) - multi_names = self._multi_names - self._multi_names = self._single_names - self._single_names = multi_names - if len(self._multi_names) > 0: - rows = [ - [ - self.control.GetCommData( - trcode, recordname, i, name - ).strip() - for name in self._multi_names - ] - for i in range(repeat_cnt) - ] - response.multi_data.names.extend(self._multi_names) - for row in rows: - if self._is_stop_condition(row): - should_stop = True - break - response.multi_data.values.add().values.extend(row) - - if len(self._single_names) > 0: - values = [ - self.control.GetCommData(trcode, recordname, 0, name).strip() - for name in self._single_names - ] - response.single_data.names.extend(self._single_names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - if should_stop: - self._scrnnos_completed[scrnno] = True - if all(self._scrnnos_completed.values()): - self.observer.on_completed() - return - else: - try: - raise KiwoomOpenApiPlusError("Should not reach here") - except KiwoomOpenApiPlusError as e: - self.observer.on_error(e) - return - - def OnEventConnect(self, errcode): - if errcode < 0: - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) - self.observer.on_error(error) - return - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): - msg_pattern = r"^[^(]+\((-?[0-9]+)\)$" - match = re.match(msg_pattern, msg) - if match: - errcode = match.group(1) - errcode = int(errcode) - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode, msg) - self.observer.on_error(error) - return diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.py deleted file mode 100644 index 61eff6aa..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler.py +++ /dev/null @@ -1,29 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) - - -class KiwoomOpenApiPlusLoadConditionEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc): - def __init__(self, control, context, request): - super().__init__(control, context) - self._request = request - - def on_enter(self): - KiwoomOpenApiPlusError.try_or_raise_boolean( - self.control.GetConditionLoad(), "Failed to load condition" - ) - - def OnReceiveConditionVer(self, ret, msg): - if ret != 1: - error = KiwoomOpenApiPlusError(msg) - self.observer.on_error(error) - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveConditionVer" - response.arguments.add().long_value = ret - response.arguments.add().string_value = msg - self.observer.on_next(response) - self.observer.on_completed() diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.py deleted file mode 100644 index 69986d77..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler.py +++ /dev/null @@ -1,115 +0,0 @@ -import datetime - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler import ( - KiwoomOpenApiPlusEventHandler, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusLoggingEventHandler(KiwoomOpenApiPlusEventHandler, Logging): - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - _datalength, - _errorcode, - _message, - _splmmsg, - ): - self.logger.debug( - "OnReceiveTrData(%r, %r, %r, %r, %r)", - scrnno, - rqname, - trcode, - recordname, - prevnext, - ) - - def OnReceiveRealData(self, code, realtype, realdata): - self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata) - if code == "09" and realtype == "장시작시간": - signal_type = self.control.GetCommRealData(code, 215) - current_time = self.control.GetCommRealData(code, 20) - estimated_remaining_time = self.control.GetCommRealData(code, 214) - signal_type_msg = { - # 아래는 문서에서 확인 가능 - "0": "장시작전(동시호가시작,이후1분단위)", - "2": "장종료전(동시호가시작,이후1분단위)", - "3": "장시작(동시호가종료)", - "4": "장종료(동시호가종료)", - "8": "장종료(시간내용없음)", - "9": "장마감(시간내용없음)", - # 이후는 추정 - "s": "선물옵션장종료전(동시호가시작)", # 17번반복 - "a": "장후시간외종가시작", - "e": "선물옵션장종료(동시호가종료)", # 17번반복 - "b": "장후시간외종가종료", - "c": "시간외단일가시작", - "d": "시간외단일가종료", - }.get(signal_type, "알수없음") - if signal_type not in ["8", "9"]: - current_time = datetime.datetime.strptime(current_time, "%H%M%S") - else: - current_time = datetime.datetime.now() - ert = datetime.datetime.strptime(estimated_remaining_time, "%H%M%S") - estimated_remaining_time = datetime.timedelta( - hours=ert.hour, minutes=ert.minute, seconds=ert.second - ) - self.logger.debug( - "%s, %s remaining", signal_type_msg, estimated_remaining_time - ) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - """ - [OnReceiveMsg()이벤트] - - OnReceiveMsg( - BSTR sScrNo, // 화면번호 - BSTR sRQName, // 사용자 구분명 - BSTR sTrCode, // TR이름 - BSTR sMsg // 서버에서 전달하는 메시지 - ) - - 서버통신 후 수신한 메시지를 알려줍니다. - 메시지에는 6자리 코드번호가 포함되는데 이 코드번호는 통보없이 수시로 변경될 수 있습니다. 따라서 주문이나 오류관련처리를 - 이 코드번호로 분류하시면 안됩니다. - """ - self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg) - - if msg == "전문 처리 실패(-22)": - self.logger.warning("Server might have ended connection abruptly") - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist) - - def OnEventConnect(self, errcode): - self.logger.debug("OnEventConnect(%r)", errcode) - - def OnReceiveRealCondition( - self, code, condition_type, condition_name, condition_index - ): - self.logger.debug( - "OnReceiveRealCondition(%r, %r, %r, %r)", - code, - condition_type, - condition_name, - condition_index, - ) - - def OnReceiveTrCondition( - self, scrnno, codelist, condition_name, condition_index, prevnext - ): - self.logger.debug( - "OnReceiveTrCondition(%r, %r, %r, %r, %r)", - scrnno, - codelist, - condition_name, - condition_index, - prevnext, - ) - - def OnReceiveConditionVer(self, ret, msg): - self.logger.debug("OnReceiveConditionVer(%r, %r)", ret, msg) diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.py deleted file mode 100644 index e65ebb2a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler.py +++ /dev/null @@ -1,42 +0,0 @@ -from google.protobuf.json_format import MessageToDict - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) - - -class KiwoomOpenApiPlusLoginEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc): - def __init__(self, control, request, context): - super().__init__(control, context) - self._request = request - - if self._request.HasField("credentials"): - self._credentials = self._request.credentials - self._credentials = MessageToDict( - self._credentials, preserving_proto_field_name=True - ) - else: - self._credentials = None - - def on_enter(self): - if self._credentials is not None: - self.control.DisableAutoLogin() - KiwoomOpenApiPlusError.try_or_raise(self.control.CommConnect()) - self.control.LoginUsingPywinauto(self._credentials) - else: - KiwoomOpenApiPlusError.try_or_raise(self.control.CommConnect()) - - def OnEventConnect(self, errcode): - if errcode < 0: - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) - self.observer.on_error(error) - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnEventConnect" - response.arguments.add().long_value = errcode - self.observer.on_next(response) - self.observer.on_completed() diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.py deleted file mode 100644 index 0f7c8b9f..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler.py +++ /dev/null @@ -1,343 +0,0 @@ -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusBaseOrderEventHandler( - KiwoomOpenApiPlusEventHandlerForGrpc, Logging -): - def __init__(self, control, context): - super().__init__(control, context) - - self._single_names = ["주문번호"] - self._multi_names = [] - - self._is_stop_condition = lambda row: False - self._inputs = {} - - self._listen_msg = True - - def ResponseForOnReceiveMsg(self, scrnno, rqname, trcode, msg): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveMsg" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = msg - - return response - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - if self._listen_msg: - response = self.ResponseForOnReceiveMsg(scrnno, rqname, trcode, msg) - self.observer.on_next(response) - - # 아래는 개발과정에서 확인 용도 - # 키움에서도 경고하지만 메시지의 코드로 판단하는건 위험함 (게다가 모의투자만 해당) - if trcode == "KOA_NORMAL_BUY_KP_ORD": - if msg == "[00Z218] 모의투자 장종료 상태입니다": - self.logger.warning("Market is closed") - elif msg == "[00Z217] 모의투자 장시작전입니다": - self.logger.warning("Market is before opening") - elif msg == "[00Z237] 모의투자 단가를 입력하지 않는 호가입니다.": - self.logger.warning("Price is given but should not") - elif msg == "[00Z112] 모의투자 정상처리 되었습니다": - self.logger.debug("Order processed successfully") - elif trcode == "KOA_NORMAL_KP_CANCEL": - if msg == "[00Z924] 모의투자 취소수량이 취소가능수량을 초과합니다": - self.logger.warning("Not enough amount to cancel") - - def ResponseForOnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - - should_stop = prevnext in ["", "0"] # pylint: disable=unused-variable - repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) - - if len(self._single_names) > 0: - values = [ - self.control.GetCommData(trcode, recordname, 0, name).strip() - for name in self._single_names - ] - response.single_data.names.extend(self._single_names) - response.single_data.values.extend(values) - - if repeat_cnt > 0 and len(self._multi_names) > 0: - rows = [ - [ - self.control.GetCommData(trcode, recordname, i, name).strip() - for name in self._multi_names - ] - for i in range(repeat_cnt) - ] - response.multi_data.names.extend(self._multi_names) - for row in rows: - if self._is_stop_condition(row): - should_stop = True - break - response.multi_data.values.add().values.extend(row) - - return response - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - order_no = self.control.GetCommData(trcode, recordname, 0, "주문번호").strip() - if order_no: - response = self.ResponseForOnReceiveTrData( - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ) - self.observer.on_next(response) - - should_stop = prevnext in ["", "0"] - if not should_stop: - self.logger.warning("Unexpected to have prevnext for order tr data.") - - def ResponseForOnReceiveChejanData(self, gubun, itemcnt, fidlist): - fids = fidlist.rstrip(";") - fids = fids.split(";") if fids else [] - fids = [int(fid) for fid in fids] - - assert itemcnt == len(fids) - - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids - ] - values = [self.control.GetChejanData(fid).strip() for fid in fids] - - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveChejanData" - response.arguments.add().string_value = gubun - response.arguments.add().long_value = itemcnt - response.arguments.add().string_value = fidlist - - response.single_data.names.extend(names) - response.single_data.values.extend(values) - - return response - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) - self.observer.on_next(response) - - def OnEventConnect(self, errcode): - if errcode < 0: - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) - self.observer.on_error(error) - return - - -class KiwoomOpenApiPlusAllOrderEventHandler(KiwoomOpenApiPlusBaseOrderEventHandler): - - pass - - -class KiwoomOpenApiPlusOrderEventHandler( - KiwoomOpenApiPlusBaseOrderEventHandler, Logging -): - def __init__(self, control, request, context, screen_manager): - super().__init__(control, context) - - self._request = request - self._screen_manager = screen_manager - - self._rqname = request.request_name - self._scrnno = request.screen_no - self._accno = request.account_no - self._ordertype = request.order_type - self._code = request.code - self._qty = request.quantity - self._price = request.price - self._hogagb = request.quote_type - self._orgorderno = request.original_order_no - - self._order_no = None - self._should_stop = False - - def on_enter(self): - self._scrnno = self._screen_manager.borrow_screen(self._scrnno) - self.add_callback(self._screen_manager.return_screen, self._scrnno) - self.add_callback(self.control.DisconnectRealData, self._scrnno) - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedSendOrder.queuedCall( - self._rqname, - self._scrnno, - self._accno, - self._ordertype, - self._code, - self._qty, - self._price, - self._hogagb, - self._orgorderno, - ), - except_callback=self.observer.on_error, - ) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - if (rqname, scrnno) == (self._rqname, self._scrnno): - response = self.ResponseForOnReceiveMsg(scrnno, rqname, trcode, msg) - self.observer.on_next(response) - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - if (rqname, scrnno) == (self._rqname, self._scrnno): - response = self.ResponseForOnReceiveTrData( - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ) - self.observer.on_next(response) - - self._order_no = self.control.GetCommData( - trcode, recordname, 0, "주문번호" - ).strip() - if not self._order_no: - e = KiwoomOpenApiPlusError("Cannot specify order no") - self.observer.on_error(e) - return - - should_stop = prevnext in ["", "0"] - if not should_stop: - self.logger.warning("Unexpected to have prevnext for order tr data.") - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - # TODO: 정정 케이스에 대해 테스트 해보지 않음 - # TODO: 취소를 취소하는 케이스 같은건 고려하지 않음 - # TODO: 서로 같은 원주문을 정정 혹은 취소하는 케이스 사이에는 이벤트 전파가 필요할지 모르겠음 - accno = self.control.GetChejanData(9201).strip() - code = self.control.GetChejanData(9001).strip() - if accno == self._accno and code.endswith( - self._code - ): # code 비교시에 앞에 prefix 가 붙어오기 때문에 endswith 으로 비교해야됨 - if gubun == "0": # 접수와 체결시 (+ 취소 확인) - order_no = self.control.GetChejanData(9203).strip() - original_order_no = self.control.GetChejanData(904).strip() - status = self.control.GetChejanData(913).strip() - scrnno = self.control.GetChejanData(920).strip() - is_last = self.control.GetChejanData(819).strip() == "1" - if order_no in [self._order_no, self._orgorderno] or self._order_no in [ - order_no, - original_order_no, - ]: - response = self.ResponseForOnReceiveChejanData( - gubun, itemcnt, fidlist - ) - self.observer.on_next(response) - if ( - order_no == self._order_no - ): # 자기 주문 처리하는 입장 OR 취소 및 정정 당한 뒤 원주문 정보를 받는 입장 - if is_last and self._should_stop: # 취소 확인 이후 원주문 정보 받고 종료 (타) - self.observer.on_completed() - return - elif status == "접수": - pass - elif status == "체결": - orders_left = self.control.GetChejanData(902).strip() - orders_left = int(orders_left) if orders_left.isdigit() else 0 - if orders_left == 0: - self._should_stop = True # 미체결수량이 더 이상 없다면 이후 잔고 이벤트 후 종료 - elif status == "확인": - self._should_stop = True # 취소 확인 이후 원주문 정보 받고 종료 (자) - else: - e = KiwoomOpenApiPlusError( - "Unexpected order status: %s" % status - ) - self.observer.on_error(e) - return - elif order_no == self._orgorderno: # 취소하는 입장에서 원주문 정보 받는 케이스 - if is_last and self._should_stop: # 취소 확인 이후 원주문 정보 받고 종료 (자) - self.observer.on_completed() - return - elif status in ["접수", "체결"]: - pass - else: - e = KiwoomOpenApiPlusError( - "Unexpected order status: %s" % status - ) - self.observer.on_error(e) - return - elif self._order_no == original_order_no: # 취소 혹은 정정 당하는 케이스 - if status == "접수": - pass - elif status == "확인": - self._should_stop = True # 취소 확인 이후 원주문 정보 받고 종료 (타) - else: - e = KiwoomOpenApiPlusError( - "Unexpected order status: %s" % status - ) - self.observer.on_error(e) - return - elif gubun == "1": # 국내주식 잔고전달 - response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) - self.observer.on_next(response) - if self._should_stop: # 미체결수량이 더 이상 없다면 잔고 이벤트 후 종료 - self.observer.on_completed() - return - elif gubun == "4": # 파생 잔고전달 - response = self.ResponseForOnReceiveChejanData(gubun, itemcnt, fidlist) - self.observer.on_next(response) - if self._should_stop: # 미체결수량이 더 이상 없다면 잔고 이벤트 후 종료 - self.observer.on_completed() - return - else: - e = KiwoomOpenApiPlusError("Unexpected gubun value: %s" % gubun) - self.observer.on_error(e) - return diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.py deleted file mode 100644 index 5a0bbc50..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler.py +++ /dev/null @@ -1,334 +0,0 @@ -import queue -import threading - -from time import sleep - -import grpc - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator import ( - QueueBasedBufferedIterator, -) -from koapy.utils.itertools import chunk -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusRealEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): - - _num_codes_per_screen = 100 - _default_opt_type = "0" - - def __init__(self, control, request, context, screen_manager): - super().__init__(control, context) - self._request = request - self._screen_manager = screen_manager - - self._screen_no = request.screen_no - self._code_list = request.code_list - self._fid_list = request.fid_list - self._opt_type = request.opt_type - - self._infer_fids = request.flags.infer_fids - self._readable_names = request.flags.readable_names - self._fast_parse = request.flags.fast_parse - - self._code_lists = [ - codes for codes in chunk(self._code_list, self._num_codes_per_screen) - ] - - if len(self._screen_no) == 0: - self._screen_nos = [None for i in range(len(self._code_lists))] - elif len(self._screen_no) < len(self._code_lists): - self.logger.warning("Given screen nos are not sufficient.") - self._screen_nos = list(self._screen_no) + [ - None for i in range(len(self._code_lists) - len(self._screen_no)) - ] - else: - self._screen_nos = self._screen_no - - self._fid_list_joined = ";".join([str(fid) for fid in self._fid_list]) - self._opt_type_final = self._opt_type or self._default_opt_type - - def on_enter(self): - for screen_no, code_list in zip(self._screen_nos, self._code_lists): - code_list_joined = ";".join(code_list) - screen_no = self._screen_manager.borrow_screen(screen_no) - self.add_callback(self._screen_manager.return_screen, screen_no) - for code in code_list: - self.add_callback( - self.control.SetRealRemove.queuedCall, screen_no, code - ) - KiwoomOpenApiPlusError.try_or_raise( - self.control.SetRealReg.queuedCall( - screen_no, - code_list_joined, - self._fid_list_joined, - self._opt_type_final, - ).result() - ) - - def OnReceiveRealData(self, code, realtype, realdata): - if code in self._code_list: - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealData" - response.arguments.add().string_value = code - response.arguments.add().string_value = realtype - response.arguments.add().string_value = realdata - - if self._infer_fids: - fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) - else: - fids = self._fid_list - - if self._readable_names: - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) - for fid in fids - ] - else: - names = [str(fid) for fid in fids] - - if self._infer_fids and self._fast_parse: - values = realdata.split("\t") - else: - values = [self.control.GetCommRealData(code, fid) for fid in fids] - - assert len(names) == len(values) - - response.single_data.names.extend(names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - def OnEventConnect(self, errcode): - if errcode < 0: - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) - self.observer.on_error(error) - return - - -class KiwoomOpenApiPlusBidirectionalRealEventHandler( - KiwoomOpenApiPlusRealEventHandler, Logging -): - def __init__(self, control, request_iterator, context, screen_manager): - request = KiwoomOpenApiPlusService_pb2.RealRequest() - super().__init__(control, request, context, screen_manager) - - self._request_iterator = request_iterator - self._buffered_request_iterator = QueueBasedBufferedIterator( - self._request_iterator - ) - - self._fid_list = [] - self._fid_list_joined = ";".join(str(fid) for fid in self._fid_list) - - self._screen_by_code = {} - self._code_list_by_screen = {} - self._code_list = [] - - self._request_iterator_consumer = None - self._request_iterator_consumer_should_stop = False - self._request_iterator_consumer_timeout = 2.0 - - def register_code(self, code, fid_list=None): - if code in self._screen_by_code: - screen_no = self._screen_by_code[code] - opt_type = "1" - else: - screen_no = None - opt_type = "0" - - for ( - existing_screen_no, - screen_code_list, - ) in self._code_list_by_screen.items(): - if len(screen_code_list) < self._num_codes_per_screen: - screen_no = existing_screen_no - opt_type = "1" - break - - if screen_no is None: - screen_no = self._screen_manager.borrow_screen() - opt_type = "0" - - self._screen_by_code[code] = screen_no - self._code_list_by_screen.setdefault(screen_no, []).append(code) - self._code_list.append(code) - - if fid_list: - fid_list_joined = ";".join(str(fid) for fid in fid_list) - else: - fid_list_joined = self._fid_list_joined - - self.logger.debug( - "Registering code %s to screen %s with type %s", code, screen_no, opt_type - ) - - def try_to_register(retry=2, timeout=3.0): - retry_count = 0 - - def call(): - KiwoomOpenApiPlusError.try_or_raise( - self.control.SetRealReg.queuedCall( - screen_no, code, fid_list_joined, opt_type - ), - except_callback=on_error, - ) - - def on_error(e): - nonlocal retry_count - if isinstance(e, KiwoomOpenApiPlusError): - error_message = ( - f"Failed to register {code=}. Reason: {e} ({e.code})." - ) - else: - error_message = f"Failed to register {code=}. Reason: {e}." - if retry_count < retry: - retry_count += 1 - self.logger.warning( - f"{error_message} Retrying ({retry_count}/{retry}) in {timeout} ..." - ) - else: - self.logger.warning( - f"{error_message} Kiwoom server does not allow register." - ) - return - sleep(timeout) - call() - - call() - - try_to_register() - - def remove_code(self, code): - if code in self._screen_by_code: - screen_no = self._screen_by_code[code] - self.logger.debug("Removing code %s from screen %s", code, screen_no) - self.control.SetRealRemove.queuedCall(screen_no, code) - self._screen_by_code.pop(code) - self._code_list_by_screen[screen_no].remove(code) - self._code_list.remove(code) - else: - self.logger.warning( - "Given code %s is not in managed code list and cannot be removed", code - ) - - def remove_all_codes(self): - code_list = list( - self._code_list - ) # copy in order to prevent "modification while iteration" - for code in code_list: - self.remove_code(code) - - def remove_all_screens(self): - self.remove_all_codes() - screen_nos = list(self._code_list_by_screen.keys()) - for screen_no in screen_nos: - self.control.DisconnectRealData( - screen_no - ) # ensure although already removed in remove_all_codes() - self._screen_manager.return_screen(screen_no) - code_list = self._code_list_by_screen.pop(screen_no) - assert len(code_list) == 0 - - def consume_request_iterator(self): - while not self._request_iterator_consumer_should_stop: - try: - request = self._buffered_request_iterator.next( - timeout=self._request_iterator_consumer_timeout - ) - except queue.Empty: - pass - except grpc.RpcError: - break - else: - if request.HasField("register_request"): - code_list = request.register_request.code_list - fid_list = request.register_request.fid_list - for code in code_list: - self.register_code(code, fid_list) - elif request.HasField("remove_request"): - code_list = request.remove_request.code_list - for code in code_list: - self.remove_code(code) - elif request.HasField("stop_request"): - self.stop() - break - elif request.HasField("initialize_request"): - self._fid_list = request.initialize_request.fid_list - self._fid_list_joined = ";".join(str(fid) for fid in self._fid_list) - self._infer_fids = request.initialize_request.flags.infer_fids - self._infer_fids = True - self._readable_names = ( - request.initialize_request.flags.readable_names - ) - self._fast_parse = request.initialize_request.flags.fast_parse - self.remove_all_codes() - else: - raise KiwoomOpenApiPlusError("Unexpected request") - - def stop_request_iterator_consumer(self): - if ( - self._request_iterator_consumer is not None - and self._request_iterator_consumer.is_alive() - ): - self._request_iterator_consumer_should_stop = True - self._request_iterator_consumer.join() - - def start_request_iterator_consumer(self): - self.stop_request_iterator_consumer() - self._request_iterator_consumer_should_stop = False - self._request_iterator_consumer = threading.Thread( - target=self.consume_request_iterator, daemon=True - ) - self._request_iterator_consumer.start() - - def on_enter(self): - self.start_request_iterator_consumer() - - def on_exit(self, exc_type=None, exc_value=None, traceback=None): - self.stop_request_iterator_consumer() - self.remove_all_screens() - - def OnReceiveRealData(self, code, realtype, realdata): - if code in self._code_list: - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveRealData" - response.arguments.add().string_value = code - response.arguments.add().string_value = realtype - response.arguments.add().string_value = realdata - - if self._infer_fids: - fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) - else: - fids = self._fid_list - - if self._readable_names: - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) - for fid in fids - ] - else: - names = [str(fid) for fid in fids] - - if self._infer_fids and self._fast_parse: - values = realdata.split("\t") - else: - values = [self.control.GetCommRealData(code, fid) for fid in fids] - - assert len(names) == len(values) - - response.single_data.names.extend(names) - response.single_data.values.extend(values) - - self.observer.on_next(response) diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.py deleted file mode 100644 index 5960b969..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler.py +++ /dev/null @@ -1,172 +0,0 @@ -import operator -import re - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc import ( - KiwoomOpenApiPlusEventHandlerForGrpc, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusTrEventHandler(KiwoomOpenApiPlusEventHandlerForGrpc, Logging): - def __init__(self, control, request, context, screen_manager): - super().__init__(control, context) - self._request = request - self._screen_manager = screen_manager - - self._rqname = request.request_name - self._trcode = request.transaction_code - self._scrnno = request.screen_no - self._inputs = request.inputs - - self._trinfo = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(self._trcode) - - if self._trinfo is None: - self.logger.error("Cannot find names for trcode %s", self._trinfo) - - self._input_code = self._inputs.get("종목코드") - - self._single_names = self._trinfo.get_single_output_names() - self._multi_names = self._trinfo.get_multi_output_names() - - stop_condition = request.stop_condition - stop_condition_is_valid = ( - stop_condition is not None - and stop_condition.name is not None - and len(stop_condition.name) > 0 - and ( - stop_condition.name in self._multi_names - or stop_condition.name in self._single_names - ) - ) - - if stop_condition_is_valid: - comparator = { - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN_OR_EQUAL_TO: operator.le, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.LESS_THAN: operator.lt, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN_OR_EQUAL_TO: operator.ge, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.GREATER_THAN: operator.gt, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.EQUAL_TO: operator.eq, - KiwoomOpenApiPlusService_pb2.TransactionStopConditionCompartor.NOT_EQUAL_TO: operator.ne, - }.get(stop_condition.comparator, operator.le) - - if stop_condition.name in self._multi_names: - column_index_to_check = self._multi_names.index(stop_condition.name) - else: - # if it does not have multi_names, it may use single_names instead. - column_index_to_check = self._single_names.index(stop_condition.name) - - def is_stop_condition(row): - return comparator(row[column_index_to_check], stop_condition.value) - - else: - - def is_stop_condition(_): - return False - - self._is_stop_condition = is_stop_condition - - def on_enter(self): - self._scrnno = self._screen_manager.borrow_screen(self._scrnno) - self.add_callback(self._screen_manager.return_screen, self._scrnno) - self.add_callback(self.control.DisconnectRealData, self._scrnno) - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommRqData.queuedCall( - self._rqname, self._trcode, 0, self._scrnno, self._inputs - ), - except_callback=self.observer.on_error, - ) - - def OnReceiveTrData( - self, - scrnno, - rqname, - trcode, - recordname, - prevnext, - datalength, - errorcode, - message, - splmmsg, - ): - if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): - response = KiwoomOpenApiPlusService_pb2.ListenResponse() - response.name = "OnReceiveTrData" - response.arguments.add().string_value = scrnno - response.arguments.add().string_value = rqname - response.arguments.add().string_value = trcode - response.arguments.add().string_value = recordname - response.arguments.add().string_value = prevnext - - should_stop = prevnext in ["", "0"] - repeat_cnt = self.control.GetRepeatCnt(trcode, recordname) - - if repeat_cnt > 0: - if len(self._multi_names) == 0: - self.logger.warning( - "Repeat count greater than 0, but no multi data names available, fallback to sigle data names" - ) - self._single_names, self._multi_names = ( - self._multi_names, - self._single_names, - ) - if len(self._multi_names) > 0: - rows = [ - [ - self.control.GetCommData( - trcode, recordname, i, name - ).strip() - for name in self._multi_names - ] - for i in range(repeat_cnt) - ] - response.multi_data.names.extend(self._multi_names) - for row in rows: - if self._is_stop_condition(row): - should_stop = True - break - response.multi_data.values.add().values.extend(row) - - if len(self._single_names) > 0: - values = [ - self.control.GetCommData(trcode, recordname, 0, name).strip() - for name in self._single_names - ] - response.single_data.names.extend(self._single_names) - response.single_data.values.extend(values) - - self.observer.on_next(response) - - if should_stop: - self.observer.on_completed() - else: - KiwoomOpenApiPlusError.try_or_raise( - self.control.RateLimitedCommRqData.queuedCall( - rqname, trcode, int(prevnext), scrnno, self._inputs - ), - except_callback=self.observer.on_error, - ) - - def OnEventConnect(self, errcode): - if errcode < 0: - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode) - self.observer.on_error(error) - return - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - if (rqname, trcode, scrnno) == (self._rqname, self._trcode, self._scrnno): - msg_pattern = r"^[^(]+\((-?[0-9]+)\)$" - match = re.match(msg_pattern, msg) - if match: - errcode = match.group(1) - errcode = int(errcode) - error = KiwoomOpenApiPlusNegativeReturnCodeError(errcode, msg) - self.observer.on_error(error) - return diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/event/__init__.py b/koapy/backend/kiwoom_open_api_plus/grpc/event/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/tools/__init__.py b/koapy/backend/kiwoom_open_api_plus/grpc/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.py b/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.py deleted file mode 100644 index 01ea4def..00000000 --- a/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto.py +++ /dev/null @@ -1,36 +0,0 @@ -import subprocess - -from pathlib import Path - - -def compile_proto(): - proto_filename = "KiwoomOpenApiPlusService.proto" - file_path = Path(__file__) - file_dir = file_path.parent - project_dir = file_dir.parent.parent.parent.parent.parent - proto_path = project_dir - proto_filepath = ( - proto_path - / "koapy" - / "backend" - / "kiwoom_open_api_plus" - / "grpc" - / proto_filename - ) - python_out = project_dir - grpc_python_out = python_out - cmd = [ - "python", - "-m", - "grpc_tools.protoc", - "--proto_path=%s" % str(proto_path), - "--python_out=%s" % str(python_out), - "--grpc_python_out=%s" % str(grpc_python_out), - str(proto_filepath), - ] - print(" ".join(cmd)) - subprocess.check_call(cmd, cwd=project_dir) - - -if __name__ == "__main__": - compile_proto() diff --git a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.py b/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.py deleted file mode 100644 index 70efd51e..00000000 --- a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler.py +++ /dev/null @@ -1,165 +0,0 @@ -import datetime -import re - -from typing import Optional - -import pytz - -from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication import ( - KiwoomOpenApiPlusManagerApplication, -) -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler import ( - QDialogHandler, -) -from koapy.compat.pyside2.QtCore import QObject -from koapy.compat.pywinauto import Desktop, WindowSpecification -from koapy.compat.pywinauto.findwindows import ElementNotFoundError -from koapy.utils.logging.Logging import Logging - - -class DialogToHandle: - def should_handle(self, dialog: WindowSpecification) -> bool: - ... - - def handle(self, dialog: WindowSpecification): - ... - - def handle_if_needed(self, dialog: WindowSpecification): - if self.should_handle(dialog): - return self.handle(dialog) - - -class KiwoomOpenApiPlusDialogToHandle(DialogToHandle, Logging): - @classmethod - def should_handle_by_title(cls, dialog: WindowSpecification, title: str): - try: - cls.logger.debug("Checking dialog title") - dialog_text = dialog.wrapper_object().window_text() - except ElementNotFoundError: - cls.logger.warning("Could not find dialog to check") - else: - return dialog_text == title - - @classmethod - def handle_by_clicking_button(cls, dialog: WindowSpecification): - try: - cls.logger.debug("Clicking confirm button on dialog") - dialog["Button"].click() - except ElementNotFoundError: - cls.logger.warning("Could not find dialog to confirm") - - @classmethod - def handle_by_emiting_should_restart_signal( - cls, - app: KiwoomOpenApiPlusManagerApplication, - restart_type: KiwoomOpenApiPlusManagerApplication.RestartType, - ): - cls.logger.debug("Restarting based on the dialog's instruction") - app.shouldRestart.emit(restart_type) - - def __init__( - self, - title: Optional[str] = None, - time: Optional[datetime.time] = None, - body: Optional[str] = None, - app: Optional[KiwoomOpenApiPlusManagerApplication] = None, - restart_type: Optional[KiwoomOpenApiPlusManagerApplication.RestartType] = None, - ): - self._title = title - self._time = time - self._body = body - - self._app = app - self._restart_type = restart_type - - def to_specification(self) -> WindowSpecification: - desktop = Desktop(allow_magic_lookup=False) - title_re = re.escape(self._title) - specification = desktop.window(title_re=title_re) - return specification - - def should_handle(self, dialog: WindowSpecification) -> bool: - return self.should_handle_by_title(dialog, self._title) - - def handle(self, dialog: WindowSpecification): - self.handle_by_clicking_button(dialog) - if self._restart_type is not None: - self.handle_by_emiting_should_restart_signal(self._app, self._restart_type) - - def handle_if_needed(self, dialog: WindowSpecification): - if self.should_handle(dialog): - return self.handle(dialog) - - -class KiwoomOpenApiPlusDialogHandler(QDialogHandler): - def __init__( - self, - app: KiwoomOpenApiPlusManagerApplication, - parent: Optional[QObject] = None, - ): - self._app = app - self._parent = parent - - kst = pytz.timezone("Asia/Seoul") - - system_check_noticie = KiwoomOpenApiPlusDialogToHandle( - title="안녕하세요. 키움증권 입니다.", - time=datetime.time(hour=4, minute=45, tzinfo=kst), - body=""" - 안녕하세요. 키움증권 입니다. - 시스템의 안정적인 운영을 위하여 - 매일 시스템 점검을 하고 있습니다. - 점검시간은 월~토요일 (05:05 ~ 05:10) - 일요일 (04:00 ~ 04:30) 까지 입니다. - 따라서 해당 시간대에는 접속단절이 될 수 있습니다. - 참고하시기 바랍니다. - """, - app=app, - ) - connection_lost = KiwoomOpenApiPlusDialogToHandle( - title="KHOpenAPI", - time=datetime.time(hour=5, minute=5, tzinfo=kst), - body=""" - 통신 연결이 끊겼습니다. 프로그램 종료후 재접속 해주시기 바랍니다. - """, - app=app, - ) - hts_reconnect_notice = KiwoomOpenApiPlusDialogToHandle( - title="[HTS 재접속 안내]", - time=datetime.time(hour=6, minute=50, tzinfo=kst), - body=""" - 안녕하세요. 키움증권입니다. - - 오전 6시 50분 이전에 접속하신 고객님께서는 - 영웅문을 재접속하여 주시기 바랍니다. - 재접속을 하지 않을 경우 거래종목 정보, 전일 거래에 - 대한 결제분 등이 반영되지 않아 실제 잔고와 차이가 - 발생할 수 있습니다. - -키움증권- - """, - app=app, - restart_type=KiwoomOpenApiPlusManagerApplication.RestartType.RESTART_AND_RESTORE, - ) - - self._dialogs_to_handle = [ - system_check_noticie, - connection_lost, - hts_reconnect_notice, - ] - self._specifications = [ - dialog.to_specification() for dialog in self._dialogs_to_handle - ] - - super().__init__(self._specifications, self._parent) - - self.readyDialog.connect(self.onReadyDialog) - - def onReadyDialog(self, dialog: WindowSpecification): - for dialog_to_handle in self._dialogs_to_handle: - try: - # pylint: disable=unused-variable - dialog_wrapper_object = dialog.wrapper_object() - except ElementNotFoundError: - break - else: - dialog_to_handle.handle_if_needed(dialog) diff --git a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.py b/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.py deleted file mode 100644 index 1d7b737b..00000000 --- a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication.py +++ /dev/null @@ -1,778 +0,0 @@ -import datetime -import os -import sys - -from argparse import Namespace -from contextlib import ExitStack, contextmanager -from enum import Enum -from pathlib import Path -from subprocess import TimeoutExpired -from threading import Timer -from typing import List, Optional, Sequence, Tuple - -import grpc -import win32api -import win32con -import win32job -import win32process - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import ( - KiwoomOpenApiPlusServiceClient, -) -from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication import ( - KiwoomOpenApiPlusServerApplication, -) -from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler import ( - KiwoomOpenApiPlusSignalHandler, -) -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor import ( - QThreadPoolExecutor, -) -from koapy.cli.extensions.parser import ArgumentParser -from koapy.cli.utils.grpc_options import server_and_client_argument_parser -from koapy.compat.pyside2.QtCore import QProcess, QSize, QThreadPool, QUrl, Signal -from koapy.compat.pyside2.QtGui import QDesktopServices, QIcon -from koapy.compat.pyside2.QtWidgets import QApplication, QMenu, QSystemTrayIcon -from koapy.config import config, get_32bit_executable -from koapy.utils.logging import set_verbosity -from koapy.utils.logging.pyside2.QObjectLogging import QObjectLogging -from koapy.utils.subprocess import Popen - - -class KiwoomOpenApiPlusManagerApplicationArgumentParser(ArgumentParser): - def __init__(self): - self._parser = server_and_client_argument_parser - - def parse_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Namespace: - return self._parser.parse_args(args, namespace) - - def parse_known_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Tuple[Namespace, List[str]]: - return self._parser.parse_known_args(args, namespace) - - -class KiwoomOpenApiPlusServerApplicationProcess(QProcess): - def __init__(self, args, parent=None): - super().__init__(parent) - - self._args = args - self._executable = get_32bit_executable() - self._arguments = [ - "-m", - KiwoomOpenApiPlusServerApplication.__module__, - ] + self._args - - self.setProgram(self._executable) - self.setArguments(self._arguments) - self.setProcessChannelMode(QProcess.ForwardedChannels) - - self._hJob = None - self._hProcess = None - - self.started.connect(self._onStarted) - self.finished.connect(self._onFinished) - - def _onStarted(self): - processId = self.processId() - - if processId != 0: - # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s - jobAttributes = None - jobName = "" - self._hJob = win32job.CreateJobObject(jobAttributes, jobName) - extendedInfo = win32job.QueryInformationJobObject( - self._hJob, win32job.JobObjectExtendedLimitInformation - ) - basicLimitInformation = extendedInfo["BasicLimitInformation"] - basicLimitInformation[ - "LimitFlags" - ] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE - win32job.SetInformationJobObject( - self._hJob, - win32job.JobObjectExtendedLimitInformation, - extendedInfo, - ) - desiredAccess = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA - inheritHandle = False - self._hProcess = win32api.OpenProcess( - desiredAccess, - inheritHandle, - processId, - ) - win32job.AssignProcessToJobObject(self._hJob, self._hProcess) - - def _onFinished(self): - exitCode = 0 - - if self._hProcess is not None: - try: - exitCode = win32process.GetExitCodeProcess(self._hProcess) - except win32process.error: - pass - - if self._hJob is not None: - win32job.TerminateJobObject(self._hJob, exitCode) - - -class KiwoomOpenApiPlusServerApplicationSubprocess: - def __init__(self, args, parent=None): - self._args = args - self._executable = get_32bit_executable() - self._cmd = [ - self._executable, - "-m", - KiwoomOpenApiPlusServerApplication.__module__, - ] + self._args - self._proc = None - self._started = False - - def start(self): - self._proc = Popen(self._cmd) - self._started = True - - def waitForStarted(self, msecs: int = 30000) -> bool: - return self._started - - def close(self): - if self._proc is not None: - self._proc.terminate() - - def waitForFinished(self, msecs: int = 30000) -> bool: - if self._proc is not None: - secs = msecs / 1000 - try: - return_code = self._proc.wait(secs) - return return_code == 0 - except TimeoutExpired: - return False - return False - - -class KiwoomOpenApiPlusManagerApplication(QObjectLogging): - class ConnectionStatus(Enum): - DISCONNECTED = 1 - CONNECTED = 2 - - class ServerType(Enum): - SIMULATION = 1 - REAL = 2 - UNKNOWN = 3 - - class RestartType(Enum): - NO_RESTART = 1 - RESTART_ONLY = 2 - RESTART_AND_RESTORE = 3 - RESTART_AND_CONNECT = 4 - RESTART_WITH_UPDATE = 5 - RESTART_WITH_UPDATE_AND_RESTORE = 6 - RESTART_WITH_UPDATE_AND_CONNECT = 7 - - shouldRestart = Signal(RestartType) - - def __init__(self, args=()): - # Parse args - self._args = list(args) - self._argument_parser = KiwoomOpenApiPlusManagerApplicationArgumentParser() - ( - self._parsed_args, - self._remaining_args, - ) = self._argument_parser.parse_known_args(self._args[1:]) - - # Set verbosity level - self._verbose = self._parsed_args.verbose - set_verbosity(self._verbose) - - # Attributes for gprc client - self._host = self._parsed_args.host - self._port = self._parsed_args.port - - # Attributes for grpc client (SSL/TLS) - self._enable_ssl = self._parsed_args.enable_ssl - self._key_file = self._parsed_args.client_key_file - self._cert_file = self._parsed_args.client_cert_file - self._root_certs_file = self._parsed_args.client_root_certs_file - - # Start creating application for real - self.logger.debug("Creating manager application") - - # Create QApplication instance - self._app = QApplication.instance() or QApplication( - self._args[:1] + self._remaining_args - ) - - # Create this QObject after creating QApplication instance - super().__init__() - - # Capture certain signals and handle them accordingly - self._signal_handler = KiwoomOpenApiPlusSignalHandler(self, self) - self._signal_handler.signaled.connect(self._onSignal) - - # Capture dialogs from OpenAPI and handle them accordingly - from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler import ( - KiwoomOpenApiPlusDialogHandler, - ) - - self._dialog_handler = KiwoomOpenApiPlusDialogHandler(self, self) - - # Attributes for gprc client (ThreadPoolExecutor) - self._max_workers = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.client.max_workers", - 8, - ) - self._thread_pool = QThreadPool(self) - self._thread_pool.setMaxThreadCount(self._max_workers) - self._thread_pool_executor = QThreadPoolExecutor(self._thread_pool, self) - - # Prepare grpc client credentials if applicable - if self._enable_ssl: - root_certificates = None - if self._root_certs_file: - with open(self._root_certs_file, "rb") as f: - root_certificates = f.read() - private_key = None - if self._key_file: - with open(self._key_file, "rb") as f: - private_key = f.read() - certificate_chain = None - if self._cert_file: - with open(self._cert_file, "rb") as f: - certificate_chain = f.read() - self._credentials = grpc.ssl_channel_credentials( - root_certificates=root_certificates, - private_key=private_key, - certificate_chain=certificate_chain, - ) - else: - self._credentials = None - - # Initialize server subprocess and gprc client to the server - self._server_process = None - self._client = None - self._reinitializeServerProcessAndGrpcClient() - - # Restart server application whenever restart is required - self.shouldRestart.connect(self._onShouldRestart) - - # Create system tray icon - self._tray = self._createSystemTrayIcon() - - # Initialize tray icon menu by invoking related event handlers - self._onEventConnect(0) - - # Make tray icon visible - self._tray.show() - - # ============================================== - # Functions for server/client (re)initialization - # ============================================== - - def _closeClient(self): - self._client.close() - - def _closeClientIfExists(self): - if hasattr(self, "_client") and self._client is not None: - self._closeClient() - - def _closeServerProcess(self): - self._server_process.close() - self._server_process.waitForFinished() - - def _closeServerProcessIfExists(self): - if hasattr(self, "_server_process") and self._server_process is not None: - self._closeServerProcess() - - def _reinitializeServerProcessAndGrpcClient(self): - self._closeClientIfExists() - self._closeServerProcessIfExists() - - # Create server application subprocess and start that - self._server_process = KiwoomOpenApiPlusServerApplicationProcess( - self._args[1:], self - ) - self._server_process.start() - self._server_process.waitForStarted() - - # Create gRPC client - self._client = KiwoomOpenApiPlusServiceClient( - host=self._host, - port=self._port, - credentials=self._credentials, - thread_pool=self._thread_pool_executor, - ) - - # Wait for the client to be ready - self._client_timeout = 30 - assert self._client.is_ready(self._client_timeout), "Client is not ready" - - # Listen OnEventConnect event from OpenAPI - # and change some application states based on that - self._client.OnEventConnect.connect(self._onEventConnect) - - # ======================================= - # Functions for creating system tray icon - # ======================================= - - def _createIcon(self): - icon = QIcon() - filePath = Path(__file__) - iconDir = (filePath.parent / "../data/icon/manager").resolve() - - def addFilesForMode(icon, iconDir, mode): - icon.addFile( - str(iconDir / "favicon-16x16.png"), - QSize(16, 16), - mode, - ) - icon.addFile( - str(iconDir / "favicon-32x32.png"), - QSize(32, 32), - mode, - ) - icon.addFile( - str(iconDir / "apple-touch-icon.png"), - QSize(180, 180), - mode, - ) - icon.addFile( - str(iconDir / "android-chrome-192x192.png"), - QSize(192, 192), - mode, - ) - icon.addFile( - str(iconDir / "android-chrome-512x512.png"), - QSize(512, 512), - mode, - ) - - # Add files for each mode - addFilesForMode(icon, iconDir / "normal", QIcon.Normal) - addFilesForMode(icon, iconDir / "disabled", QIcon.Disabled) - addFilesForMode(icon, iconDir / "active", QIcon.Active) - - return icon - - def _createToolTip(self): - toolTip = "KOAPY Manager Application" - return toolTip - - def _createContextMenu(self): - menu = QMenu() - - # Section for actions related to connection and login - menu.addSection("Connection") - connectAction = menu.addAction("Login and connect") - connectAction.triggered.connect(self._onConnectActionTriggered) - showAccountWindowAction = menu.addAction("Show account window") - showAccountWindowAction.triggered.connect( - self._onShowAccountWindowActionTriggered - ) - enableAutoLoginAction = menu.addAction("Enable auto login") - enableAutoLoginAction.triggered.connect(self._onEnableAutoLoginActionTriggered) - checkForUpdateAction = menu.addAction("Check for update") - checkForUpdateAction.triggered.connect(self._onCheckForUpdateActionTriggered) - - # Section for displaying current status, should be disabled - menu.addSection("Status") - text = self._getConnectionStatusText(self.ConnectionStatus.DISCONNECTED) - self._connectionStatusAction = menu.addAction(text) - self._connectionStatusAction.setEnabled(False) - text = self._getServerTypeText(self.ServerType.UNKNOWN) - self._serverStatusAction = menu.addAction(text) - self._serverStatusAction.setEnabled(False) - - # Section for external links (koapy) - menu.addSection("Links") - iconDir = Path(__file__).parent / "../data/icon/external" - iconDir = iconDir.resolve() - icon = QIcon(str(iconDir / "readthedocs.png")) - documentationAction = menu.addAction(icon, "Documentation") - documentationAction.triggered.connect(self._openReadTheDocs) - icon = QIcon(str(iconDir / "github.png")) - githubAction = menu.addAction(icon, "Github") - githubAction.triggered.connect(self._openGithub) - - # Section for external links (kiwoom) - menu.addSection("Kiwoom Links") - openApiAction = menu.addAction("Kiwoom OpenAPI+ Home") - openApiAction.triggered.connect(self._openOpenApiHome) - openApiAction = menu.addAction("Kiwoom OpenAPI+ Document") - openApiAction.triggered.connect(self._openOpenApiDocument) - qnaAction = menu.addAction("Kiwoom OpenAPI+ Qna") - qnaAction.triggered.connect(self._openOpenApiQna) - - # Section for exit and restart - menu.addSection("Exit") - restartAction = menu.addAction("Restart") - restartAction.triggered.connect(self._onRestartActionTriggered) - exitAction = menu.addAction("Exit") - exitAction.triggered.connect(self._onExitActionTriggered) - - return menu - - def _createSystemTrayIcon(self): - tray = QSystemTrayIcon() - - self._icon = self._createIcon() - self._tooltip = self._createToolTip() - self._menu = self._createContextMenu() - - tray.setIcon(self._icon) - tray.setToolTip(self._tooltip) - tray.setContextMenu(self._menu) - - tray.activated.connect(self._onTrayIconActivated) # pylint: disable=no-member - - return tray - - # ========================================= - # Functions for controling tray icon states - # ========================================= - - def _updateTrayIconMode(self, mode: QIcon.Mode = QIcon.Normal): - icon = QIcon(self._icon.pixmap(16, mode)) - self._tray.setIcon(icon) - - def _getConnectionStatusText(self, status: ConnectionStatus): - text = { - self.ConnectionStatus.DISCONNECTED: "Status: Disconnected", - self.ConnectionStatus.CONNECTED: "Status: Connected", - }[status] - return text - - def _updateConnectionStatus(self, status: ConnectionStatus): - text = self._getConnectionStatusText(status) - self._connectionStatusAction.setText(text) - - def _getServerTypeText(self, server_type: ServerType): - text = { - self.ServerType.SIMULATION: "Server: Simulation", - self.ServerType.REAL: "Server: Real", - self.ServerType.UNKNOWN: "Server: Unknown", - }[server_type] - return text - - def _updateServerType(self, server_type: ServerType): - text = self._getServerTypeText(server_type) - self._serverStatusAction.setText(text) - - # ======================================= - # Functions for handling tray icon events - # ======================================= - - def _onTrayIconActivated(self, reason): - pass - - def _onExitActionTriggered(self): - self.exit() - - def _onRestartActionTriggered(self): - self._emitShouldRestart(self.RestartType.RESTART_AND_RESTORE) - - def _onConnectActionTriggered(self): - self._connect() - - def _onShowAccountWindowActionTriggered(self): - self._showAccountWindow() - - def _onEnableAutoLoginActionTriggered(self): - self._enableAutoLogin() - - def _onCheckForUpdateActionTriggered(self): - self._emitShouldRestart(self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE) - - def _openOpenApiHome(self): - openApiHomeUrl = "https://www.kiwoom.com/h/customer/download/VOpenApiInfoView" - url = QUrl(openApiHomeUrl) - QDesktopServices.openUrl(url) - - def _openOpenApiDocument(self): - openApiHomeUrl = "https://download.kiwoom.com/web/openapi/kiwoom_openapi_plus_devguide_ver_1.5.pdf" - url = QUrl(openApiHomeUrl) - QDesktopServices.openUrl(url) - - def _openOpenApiQna(self): - openApiQnaUrl = "https://www.kiwoom.com/h/common/bbs/VBbsBoardBWOAZView" - url = QUrl(openApiQnaUrl) - QDesktopServices.openUrl(url) - - def _openGithub(self): - githubUrl = "https://github.com/elbakramer/koapy" - url = QUrl(githubUrl) - QDesktopServices.openUrl(url) - - def _openReadTheDocs(self): - docUrl = "https://koapy.readthedocs.io/en/latest/" - url = QUrl(docUrl) - QDesktopServices.openUrl(url) - - # ============================== - # Functions for general behavior - # ============================== - - def _ensureConnectedAndThen(self, callback=None): - if not self._client.IsConnected(): - self.logger.debug("Connecting to OpenAPI server") - self._client.EnsureConnectedAndThen(callback) - - def _connect(self): - self._ensureConnectedAndThen() - - def _showAccountWindow(self): - self._ensureConnectedAndThen(lambda errcode: self._client.ShowAccountWindow()) - - def _enableAutoLogin(self): - self._ensureConnectedAndThen( - lambda errcode: self._client.EnsureAutoLoginEnabled() - ) - - def _emitShouldRestart(self, restart_type: Optional[RestartType] = None): - if restart_type is None: - restart_type = self.RestartType.RESTART_ONLY - self.shouldRestart.emit(restart_type) - - def _emitShouldRestartAndConnect(self): - self._emitShouldRestart(self.RestartType.RESTART_AND_CONNECT) - - def _onShouldRestart(self, restart_type: RestartType): - self._restart(restart_type) - - # =================================== - # Functions for handling other events - # =================================== - - def _onSignal(self, signal, frame): - self.logger.debug("Received %r for manager application", signal) - self.exit(signal) - - def _tryReconnect(self): - now = datetime.datetime.now() - buffer = datetime.timedelta(minutes=5) - - target = now - timediff = datetime.timedelta() - - maintanance_start_time = now.replace(hour=5, minute=5, second=0, microsecond=0) - maintanance_end_time = now.replace(hour=5, minute=10, second=0, microsecond=0) - - maintanance_start_time_sunday = now.replace( - hour=4, minute=0, second=0, microsecond=0 - ) - maintanance_end_time_sunday = now.replace( - hour=4, minute=30, second=0, microsecond=0 - ) - - is_maintanance = ( - (maintanance_start_time - buffer) < now < (maintanance_end_time + buffer) - ) - is_maintanance_sunday = ( - (maintanance_start_time_sunday - buffer) - < now - < (maintanance_end_time_sunday + buffer) - ) - is_sunday = now.weekday() == 6 - - if is_maintanance: - target = maintanance_end_time + buffer - elif is_sunday and is_maintanance_sunday: - target = maintanance_end_time_sunday + buffer - - timediff = target - now - total_seconds = timediff.total_seconds() - - if total_seconds > 0: - self.logger.warning( - "Connection lost due to maintanance, waiting until %s, then will try to reconnect", - target, - ) - # QTimer is not working, why? - # QTimer.singleShot(total_seconds * 1000, self._emitShouldRestartAndConnect) - timer = Timer(total_seconds, self._emitShouldRestartAndConnect) - timer.start() - else: - self.logger.warning( - "Connection lost unexpectedly, will try to reconnect right away" - ) - self._emitShouldRestartAndConnect() - - def _onEventConnect(self, errcode): - state = self._client.GetConnectState() - - if state == 1: - self._updateTrayIconMode(QIcon.Normal) - self._updateConnectionStatus(self.ConnectionStatus.CONNECTED) - server = self._client.GetServerGubun() - if server == "1": - self._updateServerType(self.ServerType.SIMULATION) - else: - self._updateServerType(self.ServerType.REAL) - else: - self._updateTrayIconMode(QIcon.Disabled) - self._updateConnectionStatus(self.ConnectionStatus.DISCONNECTED) - self._updateServerType(self.ServerType.UNKNOWN) - - if errcode == KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_SOCKET_CLOSED: - self.logger.error("Socket closed") - self._tryReconnect() - elif errcode == KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_CONNECT: - self.logger.error("Failed to connect") - - # ================================ - # Functions for context management - # ================================ - - def _close(self): - self._closeClientIfExists() - self._closeServerProcessIfExists() - - def close(self): - return self._close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.close() - - @contextmanager - def _execContext(self): - with ExitStack() as stack: - stack.enter_context(self._signal_handler) - stack.enter_context(self._dialog_handler) - stack.enter_context(self._thread_pool_executor) - stack.enter_context(self) - yield - - # ============================== - # Functions for public interface - # ============================== - - def __getattr__(self, name): - return getattr(self._app, name) - - def _exec(self): - with self._execContext(): - self.logger.debug("Started manager application") - return self._app.exec_() - - def _exit(self, return_code=0): - self.logger.debug("Exiting manager application") - return self._app.exit(return_code) - - def _isConnected(self): - return self._client.is_ready() and self._client.IsConnected() - - def _getAPIModulePath(self): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - module_path = API_MODULE_PATH - return module_path - - def _getAutoLoginDatPath(self): - module_path = self._getAPIModulePath() - autologin_dat = module_path / "system" / "Autologin.dat" - return autologin_dat - - def _isAutoLoginEnabled(self): - autologin_dat = self._getAutoLoginDatPath() - return autologin_dat.exists() - - def _disableAutoLogin(self): - self.logger.info("Disabling auto login") - autologin_dat = self._getAutoLoginDatPath() - if autologin_dat.exists(): - self.logger.info("Removing %s", autologin_dat) - os.remove(autologin_dat) - self.logger.info("Disabled auto login") - return True - else: - self.logger.info("Autologin is already disabled") - return False - - def _restart(self, restart_type: Optional[RestartType] = None): - self.logger.debug("Restarting server application") - - if restart_type is None: - restart_type = self.RestartType.RESTART_ONLY - - is_connected = self._isConnected() - is_autologin_enabled = self._isAutoLoginEnabled() - - should_connect_to_restore = ( - restart_type - in [ - self.RestartType.RESTART_AND_RESTORE, - self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE, - ] - and is_connected - ) - should_connect_anyway = restart_type in [ - self.RestartType.RESTART_AND_CONNECT, - self.RestartType.RESTART_WITH_UPDATE_AND_CONNECT, - ] - should_connect = should_connect_to_restore or should_connect_anyway - - should_update = restart_type in [ - self.RestartType.RESTART_WITH_UPDATE, - self.RestartType.RESTART_WITH_UPDATE_AND_RESTORE, - self.RestartType.RESTART_WITH_UPDATE_AND_CONNECT, - ] - - if should_update: - self._reinitializeServerProcessAndGrpcClient() - if is_autologin_enabled: - self._disableAutoLogin() - self._client.CommConnectAndThen() - is_updated = self._client.HandleVersionUpgradeUsingPywinauto( - self._server_process.processId() - ) - if is_updated: - self._reinitializeServerProcessAndGrpcClient() - if is_autologin_enabled: - self.logger.info("Enabling auto login back") - self._enableAutoLogin() - if is_updated: - self.logger.info("Done update, enabled auto login") - else: - self.logger.info("There was no version update, enabled auto login") - else: - self._reinitializeServerProcessAndGrpcClient() - - if should_connect: - self.logger.debug("Re-establishing connection") - self._connect() - - def exec_(self): - return self._exec() - - def exit(self, return_code=0): - return self._exit(return_code) - - def restart(self, restart_type: Optional[RestartType] = None): - return self._restart(restart_type) - - def execAndExit(self): - code = self.exec_() - sys.exit(code) - - @classmethod - def main(cls, args=None): - if args is None: - args = sys.argv - app = cls(args) - app.execAndExit() - - -if __name__ == "__main__": - KiwoomOpenApiPlusManagerApplication.main() diff --git a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.py b/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.py deleted file mode 100644 index de4f5e15..00000000 --- a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication.py +++ /dev/null @@ -1,420 +0,0 @@ -import sys - -from argparse import Namespace -from contextlib import ExitStack, contextmanager -from enum import Enum -from pathlib import Path -from typing import List, Optional, Sequence, Tuple - -import grpc - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( - KiwoomOpenApiPlusQAxWidget, -) -from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer import ( - KiwoomOpenApiPlusServiceServer, -) -from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler import ( - KiwoomOpenApiPlusSignalHandler, -) -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor import ( - QThreadPoolExecutor, -) -from koapy.cli.extensions.parser import ArgumentParser -from koapy.cli.utils.grpc_options import ( - server_and_client_argument_parser, - server_argument_parser, -) -from koapy.compat.pyside2.QtCore import QSize, QThreadPool -from koapy.compat.pyside2.QtGui import QIcon -from koapy.compat.pyside2.QtWidgets import QApplication, QMenu, QSystemTrayIcon -from koapy.config import config -from koapy.utils.logging import set_verbosity -from koapy.utils.logging.pyside2.QObjectLogging import QObjectLogging - - -class KiwoomOpenApiPlusServerApplicationArgumentParser(ArgumentParser): - def __init__(self): - self._server_argument_parser = server_argument_parser - self._server_and_client_argument_parser = server_and_client_argument_parser - - def _merge_results( - self, - server_namespace, - server_and_client_namespace, - server_args=None, - server_and_client_args=None, - ): - namespace = Namespace() - - # copy server namespace values - for key, value in vars(server_namespace).items(): - setattr(namespace, key, value) - - # set aliases - namespace.host = server_namespace.bind_address - - # copy fallback options to main options - if not namespace.key_file and server_and_client_namespace.server_key_file: - namespace.key_file = server_and_client_namespace.server_key_file - if not namespace.cert_file and server_and_client_namespace.server_cert_file: - namespace.cert_file = server_and_client_namespace.server_cert_file - if ( - not namespace.root_certs_file - and server_and_client_namespace.server_root_certs_file - ): - namespace.root_certs_file = ( - server_and_client_namespace.server_root_certs_file - ) - - if server_args is not None and server_and_client_args is not None: - # filter unrecognized args - unrecognized_args = [ - arg for arg in server_args if arg in server_and_client_args - ] - return namespace, unrecognized_args - else: - return namespace - - def parse_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Namespace: - server_namespace = self._server_argument_parser.parse_args(args, namespace) - server_and_client_namespace = ( - self._server_and_client_argument_parser.parse_args(args, namespace) - ) - namespace = self._merge_results( - server_namespace, - server_and_client_namespace, - ) - return namespace - - def parse_known_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Tuple[Namespace, List[str]]: - ( - server_namespace, - server_args, - ) = self._server_argument_parser.parse_known_args(args, namespace) - ( - server_and_client_namespace, - server_and_client_args, - ) = self._server_and_client_argument_parser.parse_known_args(args, namespace) - namespace, unrecognized_args = self._merge_results( - server_namespace, - server_and_client_namespace, - server_args, - server_and_client_args, - ) - return namespace, unrecognized_args - - -class KiwoomOpenApiPlusServerApplication(QObjectLogging): - class ConnectionStatus(Enum): - DISCONNECTED = 1 - CONNECTED = 2 - - class ServerType(Enum): - SIMULATION = 1 - REAL = 2 - UNKNOWN = 3 - - def __init__(self, args=()): - # Parse args - self._args = list(args) - self._argument_parser = KiwoomOpenApiPlusServerApplicationArgumentParser() - ( - self._parsed_args, - self._remaining_args, - ) = self._argument_parser.parse_known_args(self._args[1:]) - - # Set verbosity level - self._verbose = self._parsed_args.verbose - set_verbosity(self._verbose) - - # Attributes for gprc server - self._bind_address = self._parsed_args.bind_address - self._port = self._parsed_args.port - - # Attributes for grpc server (SSL/TLS) - self._key_file = self._parsed_args.key_file - self._cert_file = self._parsed_args.cert_file - self._root_certs_file = self._parsed_args.root_certs_file - self._require_client_auth = self._parsed_args.require_client_auth - - # Start creating application for real - self.logger.debug("Creating server application") - - # Create QApplication instance - self._app = QApplication.instance() or QApplication( - self._args[:1] + self._remaining_args - ) - - # Create this QObject after creating QApplication instance - super().__init__() - - # Capture certain signals and handle them accordingly - self._signal_handler = KiwoomOpenApiPlusSignalHandler(self, self) - self._signal_handler.signaled.connect(self._onSignal) - - # Attributes for gprc server (ThreadPoolExecutor) - self._max_workers = config.get_int( - "koapy.backend.kiwoom_open_api_plus.grpc.server.max_workers", - 8, - ) - self._thread_pool = QThreadPool(self) - self._thread_pool.setMaxThreadCount(self._max_workers) - self._thread_pool_executor = QThreadPoolExecutor(self._thread_pool, self) - - # Prepare grpc server credentials if applicable - if (self._key_file and self._cert_file) or self._root_certs_file: - private_key_certificate_chain_pairs = None - server_key = None - server_cert = None - if self._key_file: - with open(self._key_file, "rb") as f: - server_key = f.read() - if self._cert_file: - with open(self._cert_file, "rb") as f: - server_cert = f.read() - if server_key and server_cert: - private_key_certificate_chain_pairs = [ - (server_key, server_cert), - ] - root_certificates = None - if self._root_certs_file: - with open(self._root_certs_file, "rb") as f: - root_certificates = f.read() - require_client_auth = self._require_client_auth - self._credentials = grpc.ssl_server_credentials( - private_key_certificate_chain_pairs=private_key_certificate_chain_pairs, - root_certificates=root_certificates, - require_client_auth=require_client_auth, - ) - else: - self._credentials = None - - # Create OpenAPI control object - self._control = KiwoomOpenApiPlusQAxWidget() - - # Create gRPC server - self._server = KiwoomOpenApiPlusServiceServer( - control=self._control, - host=self._bind_address, - port=self._port, - credentials=self._credentials, - thread_pool=self._thread_pool_executor, - ) - - # Listen OnEventConnect event from OpenAPI - # and change some application states based on that - self._control.OnEventConnect.connect(self._onEventConnect) - - # Create system tray icon - self._tray = self._createSystemTrayIcon() - - # Initialize tray icon menu by invoking related event handlers - self._onEventConnect(0) - - # Make tray icon visible - self._tray.show() - - # ======================================= - # Functions for creating system tray icon - # ======================================= - - def _createIcon(self): - icon = QIcon() - filePath = Path(__file__) - iconDir = (filePath.parent / "../data/icon/server").resolve() - - def addFilesForMode(icon, iconDir, mode): - icon.addFile( - str(iconDir / "favicon-16x16.png"), - QSize(16, 16), - mode, - ) - icon.addFile( - str(iconDir / "favicon-32x32.png"), - QSize(32, 32), - mode, - ) - icon.addFile( - str(iconDir / "apple-touch-icon.png"), - QSize(180, 180), - mode, - ) - icon.addFile( - str(iconDir / "android-chrome-192x192.png"), - QSize(192, 192), - mode, - ) - icon.addFile( - str(iconDir / "android-chrome-512x512.png"), - QSize(512, 512), - mode, - ) - - # Add files for each mode - addFilesForMode(icon, iconDir / "normal", QIcon.Normal) - addFilesForMode(icon, iconDir / "disabled", QIcon.Disabled) - addFilesForMode(icon, iconDir / "active", QIcon.Active) - - return icon - - def _createToolTip(self): - toolTip = "KOAPY Server Application" - return toolTip - - def _createContextMenu(self): - menu = QMenu() - - # Section for displaying current status, should be disabled - menu.addSection("Status") - text = self._getConnectionStatusText(self.ConnectionStatus.DISCONNECTED) - self._connectionStatusAction = menu.addAction(text) - self._connectionStatusAction.setEnabled(False) - text = self._getServerTypeText(self.ServerType.UNKNOWN) - self._serverStatusAction = menu.addAction(text) - self._serverStatusAction.setEnabled(False) - - # Exit button - menu.addSection("Exit") - exitAction = menu.addAction("Exit") - exitAction.triggered.connect(self._onExitButtonClicked) - - return menu - - def _createSystemTrayIcon(self): - tray = QSystemTrayIcon() - - self._icon = self._createIcon() - self._tooltip = self._createToolTip() - self._menu = self._createContextMenu() - - tray.setIcon(self._icon) - tray.setToolTip(self._tooltip) - tray.setContextMenu(self._menu) - - tray.activated.connect(self._onTrayIconActivated) # pylint: disable=no-member - - return tray - - # ========================================= - # Functions for controling tray icon states - # ========================================= - - def _updateTrayIconMode(self, mode: QIcon.Mode = QIcon.Normal): - icon = QIcon(self._icon.pixmap(16, mode)) - self._tray.setIcon(icon) - - def _getConnectionStatusText(self, status: ConnectionStatus): - text = { - self.ConnectionStatus.DISCONNECTED: "Status: Disconnected", - self.ConnectionStatus.CONNECTED: "Status: Connected", - }[status] - return text - - def _updateConnectionStatus(self, status: ConnectionStatus): - text = self._getConnectionStatusText(status) - self._connectionStatusAction.setText(text) - - def _getServerTypeText(self, server_type: ServerType): - text = { - self.ServerType.SIMULATION: "Server: Simulation", - self.ServerType.REAL: "Server: Real", - self.ServerType.UNKNOWN: "Server: Unknown", - }[server_type] - return text - - def _updateServerType(self, server_type: ServerType): - text = self._getServerTypeText(server_type) - self._serverStatusAction.setText(text) - - # ======================================= - # Functions for handling tray icon events - # ======================================= - - def _onTrayIconActivated(self, reason): - if reason == QSystemTrayIcon.DoubleClick: - self._control.showNormal() - self._control.activateWindow() - - def _onExitButtonClicked(self): - self.exit() - - # =================================== - # Functions for handling other events - # =================================== - - def _onSignal(self, signal, frame): - self.logger.debug("Received %r for server application ", signal) - self.exit(signal) - - def _onEventConnect(self, errcode): - state = self._control.GetConnectState() - if state == 1: - self._updateTrayIconMode(QIcon.Normal) - self._updateConnectionStatus(self.ConnectionStatus.CONNECTED) - server = self._control.GetServerGubun() - if server == "1": - self._updateServerType(self.ServerType.SIMULATION) - else: - self._updateServerType(self.ServerType.REAL) - else: - self._updateTrayIconMode(QIcon.Disabled) - self._updateConnectionStatus(self.ConnectionStatus.DISCONNECTED) - self._updateServerType(self.ServerType.UNKNOWN) - - # ================================ - # Functions for context management - # ================================ - - @contextmanager - def _execContext(self): - with ExitStack() as stack: - stack.enter_context(self._signal_handler) - stack.enter_context(self._thread_pool_executor) - stack.enter_context(self._server) - yield - - # ============================== - # Functions for public interface - # ============================== - - def __getattr__(self, name): - return getattr(self._app, name) - - def _exec(self): - with self._execContext(): - self.logger.debug("Started server application") - return self._app.exec_() - - def _exit(self, return_code=0): - self.logger.debug("Exiting server application") - return self._app.exit(return_code) - - def exec_(self): - return self._exec() - - def exit(self, return_code=0): - return self._exit(return_code) - - def execAndExit(self): - code = self.exec_() - sys.exit(code) - - @classmethod - def main(cls, args=None): - if args is None: - args = sys.argv - app = cls(args) - app.execAndExit() - - -if __name__ == "__main__": - KiwoomOpenApiPlusServerApplication.main() diff --git a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.py b/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.py deleted file mode 100644 index a9dc58f6..00000000 --- a/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler.py +++ /dev/null @@ -1,17 +0,0 @@ -import signal as signal_module - -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler import ( - QSignalHandler, -) - - -class KiwoomOpenApiPlusSignalHandler(QSignalHandler): - def __init__(self, app, parent=None): - self._app = app - self._parent = parent - - self._signals = [ - signal_module.SIGINT, - signal_module.SIGTERM, - ] - super().__init__(self._signals, self._parent) diff --git a/koapy/backend/kiwoom_open_api_plus/pyside2/__init__.py b/koapy/backend/kiwoom_open_api_plus/pyside2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/utils/__init__.py b/koapy/backend/kiwoom_open_api_plus/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.py b/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.py deleted file mode 100644 index 0abfa284..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous.py +++ /dev/null @@ -1,26 +0,0 @@ -from collections.abc import Iterator - -from grpc._channel import _MultiThreadedRendezvous as MultiThreadedRendezvous - - -class PipeableMultiThreadedRendezvous(Iterator): - def __init__(self, rendezvous, iterator=None): - super().__init__() - self._rendezvous = rendezvous - self._iterator = iterator or self._rendezvous - assert isinstance(self._rendezvous, MultiThreadedRendezvous) - assert isinstance(self._iterator, Iterator) - - def __next__(self): - return self._iterator.__next__() - - def pipe(self, func): - rendezvous = self._rendezvous - iterator = func(self._iterator) - return type(self)(rendezvous, iterator) - - def __getattr__(self, name): - try: - return getattr(self._rendezvous, name) - except AttributeError: - return getattr(self._iterator, name) diff --git a/koapy/backend/kiwoom_open_api_plus/utils/grpc/__init__.py b/koapy/backend/kiwoom_open_api_plus/utils/grpc/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.py b/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.py deleted file mode 100644 index 2ada1f21..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/list_conversion.py +++ /dev/null @@ -1,45 +0,0 @@ -import collections - -from functools import wraps -from inspect import signature - - -def string_to_list(s, sep=";"): - if s is None: - return s - if not isinstance(s, str) and isinstance(s, collections.abc.Iterable): - return s - return s.rstrip(sep).split(sep) if s else [] - - -def list_to_string(l, sep=";"): - if l is None: - return l - if isinstance(l, str): - return l - if not isinstance(l, collections.abc.Iterable): - return l - return sep.join(l) if l else "" - - -def convert_list_arguments(*indices): - def decorator(f): - sig = signature(f) - names = tuple(sig.parameters.keys()) - - @wraps(f) - def wrapper(*args, **kwargs): - ba = sig.bind(*args, **kwargs) - ba.apply_defaults() - for i in indices: - if isinstance(i, int): - i = names[i] - if isinstance(i, str): - ba.arguments[i] = list_to_string(ba.arguments[i]) - args = ba.args - kwargs = ba.kwargs - return f(*args, **kwargs) - - return wrapper - - return decorator diff --git a/koapy/backend/kiwoom_open_api_plus/utils/module_path.py b/koapy/backend/kiwoom_open_api_plus/utils/module_path.py deleted file mode 100644 index fae2cb2a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/module_path.py +++ /dev/null @@ -1,19 +0,0 @@ -import functools - -from pathlib import Path - -from deprecated import deprecated - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, -) - - -@deprecated -@functools.lru_cache() -def GetAPIModulePath() -> Path: - return API_MODULE_PATH - - -if __name__ == "__main__": - print(GetAPIModulePath()) diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.py deleted file mode 100644 index 5905f721..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler.py +++ /dev/null @@ -1,106 +0,0 @@ -import re - -from typing import Dict, List, Optional, Sequence, Set - -from koapy.compat.pyside2.QtCore import QObject, Signal -from koapy.compat.pywinauto import Desktop, WindowSpecification -from koapy.compat.pywinauto.findwindows import ElementNotFoundError -from koapy.compat.pywinauto.timings import TimeoutError as PywinautoTimeoutError -from koapy.utils.logging.pyside2.QThreadLogging import QThreadLogging - - -class QDialogHandler(QThreadLogging): - - readyDialog = Signal(WindowSpecification) - notReadyDialog = Signal(WindowSpecification) - - def __init__( - self, - specifications: Optional[Sequence[WindowSpecification]] = None, - parent: Optional[QObject] = None, - ): - QThreadLogging.__init__(self, parent) - - self._specifications: List[WindowSpecification] = ( - specifications and list(self._specifications) or [] - ) - - self._dialogs_not_ready: Set[WindowSpecification] = set(self._specifications) - self._dialogs_ready: Set[WindowSpecification] = set() - - self._text_by_dialog: Dict[WindowSpecification, str] = {} - - self._should_stop = False - - self._timeout = 1 / len(self._dialogs_not_ready) - self._retry_interval = self._timeout / 5 - - assert self._timeout >= self._retry_interval * 2 - - @classmethod - def from_titles(cls, titles: Sequence[str], allow_magic_lookup: bool = False): - titles_escaped = [re.escape(title) for title in titles] - desktop = Desktop(allow_magic_lookup=allow_magic_lookup) - specifications = [ - desktop.window(title_re=title_re) for title_re in titles_escaped - ] - return cls(specifications) - - def get_text_of_dialog( - self, - dialog: WindowSpecification, - default: Optional[str] = None, - ): - if dialog in self._text_by_dialog: - dialog_text = self._text_by_dialog[dialog] - else: - try: - dialog_text = dialog.wrapper_object().window_text() - except ElementNotFoundError: - dialog_text = default - else: - self._text_by_dialog[dialog] = dialog_text - return dialog_text - - def run(self): - while not self._should_stop: - for dialog in list(self._dialogs_not_ready): - try: - dialog.wait("ready", self._timeout, self._retry_interval) - except (PywinautoTimeoutError, ElementNotFoundError): - continue - else: - dialog_text = self.get_text_of_dialog(dialog) - self.logger.debug("Dialog found: %s", dialog_text) - self._dialogs_not_ready.remove(dialog) - self._dialogs_ready.add(dialog) - self.readyDialog.emit(dialog) - - for dialog in list(self._dialogs_ready): - try: - dialog.wait_not("ready", self._timeout, self._retry_interval) - except (PywinautoTimeoutError, ElementNotFoundError): - continue - else: - dialog_text = self.get_text_of_dialog(dialog) or "(Unknown)" - self.logger.debug("Dialog closed: %s", dialog_text) - self._dialogs_ready.remove(dialog) - self._dialogs_not_ready.add(dialog) - self.notReadyDialog.emit(dialog) - - def stop(self): - self._should_stop = True - - def wait_for_termination(self, timeout=None): - if timeout is not None: - return self.wait(timeout) - else: - return self.wait() - - def __enter__(self): - self.start() - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.stop() - self.wait_for_termination() diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QRateLimitedExecutor.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QRateLimitedExecutor.py deleted file mode 100644 index d6ce571a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QRateLimitedExecutor.py +++ /dev/null @@ -1,164 +0,0 @@ -from __future__ import annotations - -import atexit -import queue -import time - -from concurrent.futures import Executor, Future -from functools import update_wrapper -from queue import Queue -from threading import RLock -from typing import Any, Callable, Dict, Optional, Sequence - -from koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSlotLikeExecutor import ( - QSlotLikeCallable, -) -from koapy.compat.pyside2.QtCore import QObject -from koapy.utils.logging.Logging import Logging -from koapy.utils.logging.pyside2.QThreadLogging import QThreadLogging -from koapy.utils.rate_limiting.RateLimiter import RateLimiter - - -class QRateLimitedExecutorRunnable(Logging): - def __init__( - self, - future: Future, - fn: Callable, - args: Optional[Sequence[Any]] = None, - kwargs: Optional[Dict[str, Any]] = None, - ): - self._future = future - self._fn = fn - self._args = () - self._kwargs = {} - - if args: - self._args = args - if kwargs: - self._kwargs = kwargs - - def run(self): - if not self._future.set_running_or_notify_cancel(): - return - try: - result = self._fn(*self._args, **self._kwargs) - except BaseException as exc: # pylint: disable=broad-except - self.logger.exception( - "Exception while running QRateLimitedExecutorRunnable" - ) - self._future.set_exception(exc) - # break a reference cycle with the exception 'exc' - self = None # pylint: disable=self-cls-assignment - else: - self._future.set_result(result) - - def cancel(self): - return self._future.cancel() - - def result(self): - return self._future.result() - - -class QRateLimitedExecutorDecoratedFunction(Logging): - def __init__( - self, - func: QSlotLikeCallable, - limiter: RateLimiter, - executor: QRateLimitedExecutor, - ): - self._func = func - self._limiter = limiter - self._executor = executor - - update_wrapper(self, self._func, updated=[]) - - def _checkAndSleepIfNecessary(self, *args, **kwargs): - sleep_seconds = self._limiter.check_sleep_seconds(*args, **kwargs) - if sleep_seconds > 0: - if sleep_seconds > 1: - self.logger.debug( - "Rate limiting function call %s(...), sleeping for %f seconds...", - self._func.__name__, - sleep_seconds, - ) - time.sleep(sleep_seconds) - self._limiter.add_call_history(*args, **kwargs) - - def _directCallFn(self, *args, **kwargs): - self._checkAndSleepIfNecessary(*args, **kwargs) - return self._func.directCall(*args, **kwargs) - - def directCall(self, *args, **kwargs): - return self._directCallFn(*args, **kwargs) - - def _queuedCallFn(self, *args, **kwargs): - self._checkAndSleepIfNecessary(*args, **kwargs) - return self._func.queuedCall(*args, **kwargs).result() - - def queuedCall(self, *args, **kwargs): - return self._executor.submit(self._queuedCallFn, *args, **kwargs) - - def __call__(self, *args, **kwargs): - return self.directCall(*args, **kwargs) - - def __getattr__(self, name): - return getattr(self._func, name) - - -class QRateLimitedExecutor(QThreadLogging, Executor): - def __init__(self, limiter: RateLimiter, parent: Optional[QObject] = None): - QThreadLogging.__init__(self, parent) - Executor.__init__(self) - - self._limiter = limiter - self._parent = parent - - self._runnable_queue: Queue = Queue() - self._sentinel = object() - - self._shutdown = False - self._shutdown_lock = RLock() - - atexit.register(self.shutdown) - - def __del__(self): - atexit.unregister(self.shutdown) - - def run(self): - while True: - runnable = self._runnable_queue.get() - if runnable is not self._sentinel: - runnable.run() - continue - if self._shutdown: - return - - def submit(self, fn: Callable, /, *args, **kwargs): - with self._shutdown_lock: - if self._shutdown: - raise RuntimeError("Cannot schedule new futures after shutdown") - future = Future() - runnable = QRateLimitedExecutorRunnable(future, fn, args, kwargs) - self._runnable_queue.put(runnable) - return future - - def shutdown( - self, wait: bool = True, cancel_futures: bool = False - ): # pylint: disable=arguments-differ - with self._shutdown_lock: - self._shutdown = True - if cancel_futures: - while True: - try: - runnable = self._runnable_queue.get_nowait() - except queue.Empty: - break - if runnable is not self._sentinel: - runnable.cancel() - self._runnable_queue.put(self._sentinel) - if wait: - self.wait() - - def wrapCallable(self, func: Callable): - wrapped = QRateLimitedExecutorDecoratedFunction(func, self._limiter, self) - return wrapped diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.py deleted file mode 100644 index d1a66151..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler.py +++ /dev/null @@ -1,128 +0,0 @@ -import signal as signal_module -import socket - -from signal import Signals -from types import FrameType -from typing import Iterable, Optional, overload - -from koapy.compat.pyside2.QtCore import QObject, Signal -from koapy.compat.pyside2.QtNetwork import QAbstractSocket -from koapy.utils.logging.pyside2.QAbstractSocketLogging import QAbstractSocketLogging - - -class QSignalHandler(QAbstractSocketLogging): - - signaled = Signal(Signals, FrameType) - - @overload - def __init__(self, signals: Iterable[Signals], parent: Optional[QObject]): - ... - - @overload - def __init__(self, parent: Optional[QObject]): - ... - - def __init__(self, *args, **kwargs): - signals: Optional[Iterable[Signals]] = None - parent: Optional[QObject] = None - - args = list(args) - kwargs = dict(kwargs) - - if len(args) > 0 and not isinstance(args[0], QObject): - signals = args.pop(0) - elif "signals" in kwargs: - signals = kwargs.pop("signals") - - if len(args) > 0: - parent = args[0] - elif "parent" in kwargs: - parent = kwargs["parent"] - - self._signals = signals - self._parent = parent - - QAbstractSocketLogging.__init__( - self, QAbstractSocket.UdpSocket, *args, **kwargs - ) - - self._old_wakeup_fd = None - self._old_signal_handlers = {} - - self._wsock, self._rsock = socket.socketpair(socket.AF_INET, socket.SOCK_STREAM) - - self.readyRead.connect(self.onReadyRead) - - def onReadyRead(self): - # it is up to the library to remove any bytes from fd before calling poll or select again - # check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details - data = self.readData(1) - - # not actually using this, since file descriptor is used for wakeup purpose only - _signal = data[0] - - def emitSignal(self, signal, frame): - signal = signal_module.Signals(signal) - self.signaled.emit(signal, frame) - - def setWakeUpFileDescriptor(self, descriptor, warn_on_full_buffer=True): - old_wakeup_fd = signal_module.set_wakeup_fd( - descriptor, warn_on_full_buffer=warn_on_full_buffer - ) - # remember first time replcement only - if self._old_wakeup_fd is None: - self._old_wakeup_fd = old_wakeup_fd - return old_wakeup_fd - - def restoreWakeUpFileDescrptor(self): - if self._old_wakeup_fd is not None: - old_wakeup_fd = signal_module.set_wakeup_fd(self._old_wakeup_fd) - self._old_wakeup_fd = None - return old_wakeup_fd - - def setHandler(self, signal, handler): - old_handler = signal_module.signal(signal, handler) - # remember first time replcement only - if signal not in self._old_signal_handlers: - self._old_signal_handlers[signal] = old_handler - return old_handler - - def restoreHandler(self, signal, default=None): - if signal in self._old_signal_handlers: - if default is None: - default = signal_module.SIG_DFL - old_handler = self._old_signal_handlers.pop(signal, default) - old_handler = signal_module.signal(signal, old_handler) - return old_handler - - def restoreAllHandlers(self): - if self._old_signal_handlers: - old_signal_handlers = dict(self._old_signal_handlers) - for signal, handler in old_signal_handlers.items(): - self.restoreHandler(signal, handler) - self._old_signal_handlers = {} - - def setAll(self): - self.setSocketDescriptor(self._rsock.fileno()) - - # setting warn_on_full_buffer=False, since we are using the wakeup fd only for wakeups - # check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details - self.setWakeUpFileDescriptor(self._wsock.fileno(), warn_on_full_buffer=False) - - if self._signals: - for signal in self._signals: - self.setHandler(signal, self.emitSignal) - - def restoreAll(self): - self.restoreWakeUpFileDescrptor() - self.restoreAllHandlers() - - def __del__(self): - self.restoreAll() - - def __enter__(self): - self.setAll() - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.restoreAll() diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSlotLikeExecutor.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSlotLikeExecutor.py deleted file mode 100644 index be65132a..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSlotLikeExecutor.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import annotations - -from concurrent.futures import Executor, Future -from typing import Any, Callable, Dict, Optional, Sequence - -try: - from typing import ParamSpec, TypeVar -except ImportError: - from typing_extensions import ParamSpec - from typing import TypeVar - -from functools import update_wrapper - -from koapy.compat.pyside2.QtCore import QObject, Qt, Signal -from koapy.utils.logging.Logging import Logging - -P = ParamSpec("P") -R = TypeVar("R") - - -class QSlotLikeExecutorRunnable(Logging): - def __init__( - self, - future: Future, - fn: Callable[P, R], - args: Optional[Sequence[Any]] = None, - kwargs: Optional[Dict[str, Any]] = None, - ): - self._future = future - self._fn = fn - self._args = () - self._kwargs = {} - - if args: - self._args = args - if kwargs: - self._kwargs = kwargs - - def run(self): - if not self._future.set_running_or_notify_cancel(): - return - try: - result = self._fn(*self._args, **self._kwargs) - except BaseException as exc: # pylint: disable=broad-except - self.logger.exception("Exception while running QSlotLikeExecutorRunnable") - self._future.set_exception(exc) - # break a reference cycle with the exception 'exc' - self = None # pylint: disable=self-cls-assignment - else: - self._future.set_result(result) - - -class QSlotLikeCallable: - def __init__(self, fn: Callable[P, R], executor: QSlotLikeExecutor): - self._fn = fn - self._executor = executor - update_wrapper(self, self._fn, updated=[]) - - def directCall(self, *args: P.args, **kwargs: P.kwargs) -> R: - return self._fn(*args, **kwargs) - - def queuedCall(self, *args: P.args, **kwargs: P.kwargs) -> Future: - return self._executor.submit(self._fn, *args, **kwargs) - - def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: - return self.directCall(*args, **kwargs) - - def __getattr__(self, name): - return getattr(self._fn, name) - - -class QSlotLikeExecutor(QObject, Executor): - - readyRunnable = Signal(QSlotLikeExecutorRunnable) - - def __init__(self, parent: Optional[QObject] = None): - QObject.__init__(self, parent) - Executor.__init__(self) - self.readyRunnable.connect(self.onReadyRunnable, Qt.QueuedConnection) - - def onReadyRunnable(self, runnable: QSlotLikeExecutorRunnable): - runnable.run() - - def submit(self, fn: Callable[P, R], /, *args, **kwargs): - future = Future() - runnable = QSlotLikeExecutorRunnable(future, fn, args, kwargs) - self.readyRunnable.emit(runnable) - return future - - def wrapCallable(self, fn: Callable[P, R]) -> QSlotLikeCallable: - wrapped = QSlotLikeCallable(fn, self) - return wrapped diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.py deleted file mode 100644 index 0bca51eb..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor.py +++ /dev/null @@ -1,100 +0,0 @@ -import atexit - -from concurrent.futures import Executor, Future -from threading import RLock -from typing import Any, Callable, Dict, List, Optional, Tuple, Union, overload - -from koapy.compat.pyside2.QtCore import QObject, QRunnable, QThreadPool - - -class QThreadPoolExecutorRunnable(QRunnable): - def __init__( - self, - future: Future, - fn: Callable[..., Any], - args: Union[Tuple[Any], List[Any]], - kwargs: Dict[str, Any], - ): - super().__init__() - - self._future = future - self._fn = fn - self._args = args - self._kwargs = kwargs - - def run(self): - # pylint: disable=broad-except,self-cls-assignment - if not self._future.set_running_or_notify_cancel(): - return - try: - result = self._fn(*self._args, **self._kwargs) - except BaseException as exc: - self._future.set_exception(exc) - # break a reference cycle with the exception 'exc' - self = None - else: - self._future.set_result(result) - - -class QThreadPoolExecutor(QObject, Executor): - # pylint: disable=arguments-differ - - @overload - def __init__(self, thread_pool: QThreadPool, parent: Optional[QObject]): - ... - - @overload - def __init__(self, parent: Optional[QObject]): - ... - - def __init__(self, *args, **kwargs): - thread_pool: Optional[QThreadPool] = None - parent: Optional[QObject] = None - - args = list(args) - kwargs = dict(kwargs) - - if len(args) > 0 and isinstance(args[0], QThreadPool): - thread_pool = args.pop(0) - elif "thread_pool" in kwargs: - thread_pool = kwargs.pop("thread_pool") - - if len(args) > 0: - parent = args[0] - elif "parent" in kwargs: - parent = kwargs["parent"] - - if thread_pool is None: - thread_pool = QThreadPool(self) - - self._thread_pool = thread_pool - self._parent = parent - - QObject.__init__(self, *args, **kwargs) - Executor.__init__(self) - - self._shutdown = False - self._shutdown_lock = RLock() - - atexit.register(self.shutdown) - - def __del__(self): - atexit.unregister(self.shutdown) - - def submit(self, fn, *args, **kwargs): - with self._shutdown_lock: - if self._shutdown: - raise RuntimeError("Cannot schedule new futures after shutdown") - future = Future() - runnable = QThreadPoolExecutorRunnable(future, fn, args, kwargs) - runnable.setAutoDelete(True) - self._thread_pool.start(runnable) - return future - - def shutdown(self, wait=True, cancel_futures=False): - with self._shutdown_lock: - self._shutdown = True - if cancel_futures: - self._thread_pool.clear() - if wait: - self._thread_pool.waitForDone() diff --git a/koapy/backend/kiwoom_open_api_plus/utils/pyside2/__init__.py b/koapy/backend/kiwoom_open_api_plus/utils/pyside2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.py b/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.py deleted file mode 100644 index 9d8714b4..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys -import threading - -from queue import Queue - -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator import ( - BufferedQueueIterator, -) -from koapy.utils.logging.Logging import Logging - - -class QueueBasedBufferedIterator(BufferedQueueIterator, Logging): - - _check_timeout = 1 - _default_maxsize = 10 - - def __init__(self, iterator, queue=None, maxsize=None): - if queue is None: - if maxsize is None: - maxsize = self._default_maxsize - queue = Queue(maxsize) - - self._iterator = iterator - self._queue = queue - self._maxsize = maxsize - self._exc_info = None - - super().__init__(self._queue) - - self._thread = threading.Thread(target=self._consume_iterator, daemon=True) - self._thread.start() - - def _consume_iterator(self): - try: - for item in self._iterator: - self._queue.put(item) - except Exception: # pylint: disable=broad-except - self.logger.exception("Exception raised while consuming iterator") - self._exc_info = sys.exc_info() - - def next(self, block=True, timeout=None): - try: - item = super().next(block, timeout) - except StopIteration as e: - if self._exc_info is not None: - raise self._exc_info[1] from e - else: - raise e - else: - if self._exc_info is not None: - raise self._exc_info[1] - return item diff --git a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.py b/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.py deleted file mode 100644 index d0a30941..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver.py +++ /dev/null @@ -1,67 +0,0 @@ -from queue import Empty, Queue - -from rx.core.typing import Observer - -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator import ( - BufferedQueueIterator, -) - - -class QueueBasedIterableObserverIterator(BufferedQueueIterator): - def __init__(self, queue, sentinel): - self._queue = queue - self._sentinel = sentinel - super().__init__(self._queue) - - def next(self, block=True, timeout=None): - value, error = super().next(block, timeout) - if value == self._sentinel: - raise StopIteration - elif error is not None and isinstance(error, Exception): - raise error - return value - - def head(self): - value, error = super().head() - if value == self._sentinel: - raise Empty - elif error is not None and isinstance(error, Exception): - raise error - return value - - -class QueueBasedIterableObserver(Observer): - - _default_maxsize = 0 - _queue_get_timeout = 2 - - def __init__(self, queue=None, maxsize=None): - if queue is None: - if maxsize is None: - maxsize = self._default_maxsize - queue = Queue(maxsize) - - self._queue = queue - self._maxsize = maxsize - self._sentinel = object() - - self._iterator = QueueBasedIterableObserverIterator(self._queue, self._sentinel) - - @property - def queue(self): - return self._queue - - def on_next(self, value): - self._queue.put((value, None)) - - def on_error(self, error): - self._queue.put((None, error)) - - def on_completed(self): - self._queue.put((self._sentinel, None)) - - def __iter__(self): - return self._iterator - - def stop(self): - return self._iterator.stop() diff --git a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.py b/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.py deleted file mode 100644 index 0168838d..00000000 --- a/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator.py +++ /dev/null @@ -1,83 +0,0 @@ -import atexit - -from queue import Empty - - -class QueueIterator: - - _check_timeout = 1 - - def __init__(self, queue): - self._queue = queue - self._should_stop = False - - atexit.register(self.stop) - - def __del__(self): - atexit.unregister(self.stop) - - @property - def queue(self): - return self._queue - - def next(self, block=True, timeout=None): - if block and timeout is None: - timeout = self._check_timeout - while not self._should_stop: - try: - item = self._queue.get(block=block, timeout=timeout) - except Empty: - pass - else: - self._queue.task_done() - return item - raise StopIteration - else: - item = self._queue.get(block=block, timeout=timeout) - self._queue.task_done() - return item - - def next_nowait(self): - return self.next(block=False) - - def has_next(self): - return not self._queue.empty() - - def __iter__(self): - return self - - def __next__(self): - return self.next() - - def stop(self): - self._should_stop = True - - def enable(self): - self._should_stop = False - - -class BufferedQueueIterator(QueueIterator): - def __init__(self, queue): - super().__init__(queue) - - self._none = object() - self._head = self._none - - def next(self, block=True, timeout=None): - if self._head is not self._none: - item = self._head - self._head = self._none - return item - else: - return super().next(block, timeout) - - def has_next(self): - return self._head is not self._none or super().has_next() - - def head(self): - if self._head is not self._none: - return self._head - else: - item = self.next_nowait() # raises queue.Empty if queue is empty - self._head = item - return self._head diff --git a/koapy/backend/kiwoom_open_api_plus/utils/queue/__init__.py b/koapy/backend/kiwoom_open_api_plus/utils/queue/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_w/__init__.py b/koapy/backend/kiwoom_open_api_w/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.py deleted file mode 100644 index a84d4a3e..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable.py +++ /dev/null @@ -1,38 +0,0 @@ -from inspect import Signature - -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import ( - KiwoomOpenApiWDispatchSignature, -) - - -class KiwoomOpenApiWDynamicCallable: - def __init__(self, control, name): - self._control = control - self._name = name - self._signature = KiwoomOpenApiWDispatchSignature.from_name(self._name) - self._function = self._signature.to_pyside2_function_prototype() - self._should_test_return_type = ( - self._signature.return_annotation is not Signature.empty - ) - - def is_valid_return_type(self, result): - if self._should_test_return_type and not isinstance( - result, self._signature.return_annotation - ): - return False - return True - - def __call__(self, *args, **kwargs): - ba = self._signature.bind(*args, **kwargs) - ba.apply_defaults() - result = self._control.dynamicCall(self._function, list(ba.args)) - if not self.is_valid_return_type(result): - raise TypeError( - "Return type of %s was expected for function call %s(...), but %s was found." - % ( - self._signature.return_annotation, - self._name, - type(result), - ) - ) - return result diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.py deleted file mode 100644 index 0bae2a89..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError.py +++ /dev/null @@ -1,176 +0,0 @@ -from functools import wraps - - -class KiwoomOpenApiWError(Exception): - def __init__(self, message=None): - if message is not None: - super().__init__(message) - else: - super().__init__() - - self._message = message - - @property - def message(self): - return self._message - - @classmethod - def try_or_raise(cls, arg, message=None): - return KiwoomOpenApiWNegativeReturnCodeError.try_or_raise(arg, message) - - @classmethod - def try_or_raise_boolean(cls, arg, message): - return KiwoomOpenApiWBooleanReturnCodeError.try_or_raise(arg, message) - - -class KiwoomOpenApiWNegativeReturnCodeError(KiwoomOpenApiWError): - - OP_ERR_NONE = 0 - OP_ERR_NO_LOGIN = -1 - OP_ERR_LOGIN = -100 - OP_ERR_CONNECT = -101 - OP_ERR_VERSION = -102 - OP_ERR_TRCODE = -103 - OP_ERR_NO_REGOPENAPI = -104 - OP_ERR_SISE_OVERFLOW = -200 - OP_ERR_ORDER_OVERFLOW = -201 - OP_ERR_RQ_WRONG_INPUT = -202 - OP_ERR_ORD_WRONG_INPUT = -300 - OP_ERR_ORD_WRONG_ACCPWD = -301 - OP_ERR_ORD_WRONG_ACCNO = -302 - OP_ERR_ORD_WRONG_QTY200 = -303 - OP_ERR_ORD_WRONG_QTY400 = -304 - - MSG_ERR_NONE = "정상처리" - MSG_ERR_NO_LOGIN = "미접속상태" - MSG_ERR_LOGIN = "로그인시 접속 실패 (아이피 오류 또는 접속정보 오류)" - MSG_ERR_CONNECT = "서버 접속 실패" - MSG_ERR_VERSION = "버전처리가 실패하였습니다." - MSG_ERR_TRCODE = "TrCode 가 존재하지 않습니다." - MSG_ERR_NO_REGOPENAPI = "해외OpenAPI 미신청" - MSG_ERR_SISE_OVERFLOW = "조회과부화" - MSG_ERR_ORDER_OVERFLOW = "주문과부화" - MSG_ERR_RQ_WRONG_INPUT = "조회입력값(명칭/누락) 오류" - MSG_ERR_ORD_WRONG_INPUT = "주문입력갑 오류" - MSG_ERR_ORD_WRONG_ACCPWD = "계좌비밀번호를 입력하십시오." - MSG_ERR_ORD_WRONG_ACCNO = "타인 계좌를 사용할 수 없습니다." - MSG_ERR_ORD_WRONG_QTY200 = "경고-주문수량 200개 초과" - MSG_ERR_ORD_WRONG_QTY400 = "제한-주문수량 400개 초과" - - ERROR_MESSAGE_BY_CODE = { - OP_ERR_NONE: MSG_ERR_NONE, - OP_ERR_NO_LOGIN: MSG_ERR_NO_LOGIN, - OP_ERR_LOGIN: MSG_ERR_LOGIN, - OP_ERR_CONNECT: MSG_ERR_CONNECT, - OP_ERR_VERSION: MSG_ERR_VERSION, - OP_ERR_TRCODE: MSG_ERR_TRCODE, - OP_ERR_NO_REGOPENAPI: MSG_ERR_NO_REGOPENAPI, - OP_ERR_SISE_OVERFLOW: MSG_ERR_SISE_OVERFLOW, - OP_ERR_ORDER_OVERFLOW: MSG_ERR_ORDER_OVERFLOW, - OP_ERR_RQ_WRONG_INPUT: MSG_ERR_RQ_WRONG_INPUT, - OP_ERR_ORD_WRONG_INPUT: MSG_ERR_ORD_WRONG_INPUT, - OP_ERR_ORD_WRONG_ACCPWD: MSG_ERR_ORD_WRONG_ACCPWD, - OP_ERR_ORD_WRONG_ACCNO: MSG_ERR_ORD_WRONG_ACCNO, - OP_ERR_ORD_WRONG_QTY200: MSG_ERR_ORD_WRONG_QTY200, - OP_ERR_ORD_WRONG_QTY400: MSG_ERR_ORD_WRONG_QTY400, - } - - @classmethod - def get_error_message_by_code(cls, code, default=None): - return cls.ERROR_MESSAGE_BY_CODE.get(code, default) - - @classmethod - def check_code_or_raise(cls, code): - if code < 0: - raise cls(code) - return code - - @classmethod - def wrap_to_check_code_or_raise(cls, func): - @wraps(func) - def wrapper(*args, **kwargs): - return cls.check_code_or_raise(func(*args, **kwargs)) - - return wrapper - - @classmethod - def try_or_raise(cls, arg, message=None): - if isinstance(arg, int): - return cls.check_code_or_raise(arg) - elif callable(arg): - return cls.wrap_to_check_code_or_raise(arg) - else: - raise TypeError("Expected 'int' or 'callable' but %s found" % type(arg)) - - def __init__(self, code, message=None): - if message is None: - message = self.get_error_message_by_code(code) - - super().__init__(message) - - self._code = code - self._message = message - - def __str__(self): - return self._message - - def __repr__(self): - return "{}({!r}, {!r})".format( - self.__class__.__name__, self._code, self._message - ) - - @property - def code(self): - return self._code - - -class KiwoomOpenApiWBooleanReturnCodeError(KiwoomOpenApiWError): - - OP_ERR_SUCCESS = 1 - OP_ERR_FAILURE = 0 - - @classmethod - def check_code_or_raise(cls, code, message=None): - if not code: - raise cls(message) - return code - - @classmethod - def wrap_to_check_code_or_raise(cls, func, message=None): - @wraps(func) - def wrapper(*args, **kwargs): - return cls.check_code_or_raise(func(*args, **kwargs), message) - - return wrapper - - @classmethod - def try_or_raise(cls, arg, message=None): - if isinstance(arg, (int, bool)): - return cls.check_code_or_raise(arg, message) - elif callable(arg): - return cls.wrap_to_check_code_or_raise(arg, message) - else: - raise TypeError( - "Expected 'int', 'bool' or 'callable' but %s found" % type(arg) - ) - - def __init__(self, code, message=None): - super().__init__(message) - - self._code = code - self._message = message - - def __str__(self): - if self._message: - return self._message - else: - return self.__repr__() - - def __repr__(self): - return "{}({!r}, {!r})".format( - self.__class__.__name__, self._code, self._message - ) - - @property - def code(self): - return self._code diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.py deleted file mode 100644 index 0ff7c2fe..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler.py +++ /dev/null @@ -1,104 +0,0 @@ -from contextlib import ExitStack -from threading import RLock - -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import ( - QueueBasedIterableObserver, -) -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions import ( - KiwoomOpenApiWEventHandlerFunctions, -) -from koapy.utils.notimplemented import isimplemented - - -class KiwoomOpenApiWEventHandler(KiwoomOpenApiWEventHandlerFunctions): - def __init__(self, control): - self._control = control - self._observer = QueueBasedIterableObserver() - self._enter_count = 0 - self._should_exit = False - self._stack = ExitStack() - self._lock = RLock() - - @property - def control(self): - return self._control - - @property - def observer(self): - return self._observer - - @classmethod - def names(cls): - names = [ - name - for name in dir(KiwoomOpenApiWEventHandlerFunctions) - if name.startswith("On") - ] - return names - - def slots(self): - names = self.names() - slots = [getattr(self, name) for name in names] - names_and_slots_implemented = [ - (name, slot) for name, slot in zip(names, slots) if isimplemented(slot) - ] - return names_and_slots_implemented - - def connect(self): - for name, slot in self.slots(): - getattr(self.control, name).connect(slot) - - def disconnect(self): - for name, slot in self.slots(): - getattr(self.control, name).disconnect(slot) - - def on_enter(self): - pass - - def on_exit(self, exc_type=None, exc_value=None, traceback=None): - pass - - def add_callback(self, callback, *args, **kwargs): - self._stack.callback(callback, *args, **kwargs) - - def enter(self): - with self._lock: - self.connect() - self.on_enter() - self._should_exit = True - - def exit(self, exc_type=None, exc_value=None, traceback=None): - with self._lock: - if self._should_exit: - self.disconnect() - self.on_exit(exc_type, exc_value, traceback) - self._stack.__exit__(exc_type, exc_value, traceback) - self._should_exit = False - - def stop(self): - return self.observer.stop() - - def close(self): - self.exit() - self.stop() - - def __enter__(self): - with self._lock: - if self._enter_count == 0: - self.enter() - self._enter_count += 1 - return self - - def __exit__(self, exc_type, exc_value, traceback): - if exc_type is not None: - return self.exit(exc_type, exc_value, traceback) - with self._lock: - if self._enter_count > 0: - self._enter_count -= 1 - if self._enter_count == 0: - return self.exit(exc_type, exc_value, traceback) - return - - def __iter__(self): - with self: - return iter(self.observer) diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.py deleted file mode 100644 index 41403832..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions.py +++ /dev/null @@ -1,23 +0,0 @@ -from koapy.utils.notimplemented import notimplemented - - -class KiwoomOpenApiWEventHandlerFunctions: - @notimplemented - def OnEventConnect(self, errcode): - raise NotImplementedError - - @notimplemented - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - raise NotImplementedError - - @notimplemented - def OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext): - raise NotImplementedError - - @notimplemented - def OnReceiveRealData(self, code, realtype, realdata): - raise NotImplementedError - - @notimplemented - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - raise NotImplementedError diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.py deleted file mode 100644 index 94e75a68..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler.py +++ /dev/null @@ -1,28 +0,0 @@ -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler import ( - KiwoomOpenApiWEventHandler, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiWLoggingEventHandler(KiwoomOpenApiWEventHandler, Logging): - def OnReceiveTrData(self, scrnno, rqname, trcode, recordname, prevnext): - self.logger.debug( - "OnReceiveTrData(%r, %r, %r, %r, %r)", - scrnno, - rqname, - trcode, - recordname, - prevnext, - ) - - def OnReceiveRealData(self, code, realtype, realdata): - self.logger.debug("OnReceiveRealData(%r, %r, %r)", code, realtype, realdata) - - def OnReceiveMsg(self, scrnno, rqname, trcode, msg): - self.logger.debug("OnReceiveMsg(%r, %r, %r, %r)", scrnno, rqname, trcode, msg) - - def OnReceiveChejanData(self, gubun, itemcnt, fidlist): - self.logger.debug("OnReceiveChejanData(%r, %r, %r)", gubun, itemcnt, fidlist) - - def OnEventConnect(self, errcode): - self.logger.debug("OnEventConnect(%r)", errcode) diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.py deleted file mode 100644 index 78c8dcc3..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget.py +++ /dev/null @@ -1,116 +0,0 @@ -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable import ( - KiwoomOpenApiWDynamicCallable, -) -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler import ( - KiwoomOpenApiWLoggingEventHandler, -) -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin import ( - KiwoomOpenApiWQAxWidgetMixin, -) -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector import ( - KiwoomOpenApiWSignalConnector, -) -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import ( - KiwoomOpenApiWDispatchSignature, - KiwoomOpenApiWEventHandlerSignature, -) -from koapy.compat.pyside2.QtAxContainer import QAxWidget -from koapy.compat.pyside2.QtCore import QEvent, Qt -from koapy.compat.pyside2.QtWidgets import QWidget -from koapy.utils.logging.pyside2.QWidgetLogging import QWidgetLogging -from koapy.utils.platform import is_32bit - - -class KiwoomOpenApiWQAxWidget(QWidgetLogging, KiwoomOpenApiWQAxWidgetMixin): - - CLSID = "{D1ACAB7D-A3AF-49E4-9004-C9E98344E17A}" - - METHOD_NAMES = KiwoomOpenApiWDispatchSignature.names() - EVENT_NAMES = KiwoomOpenApiWEventHandlerSignature.names() - - def __init__(self, *args, **kwargs): - # Check 32bit requirement - assert is_32bit(), "Control object should be created in 32bit environment" - - # Process arguments - control = None - parent = None - window_flags = None - - args = list(args) - kwargs = dict(kwargs) - - if len(args) > 0 and isinstance(args[0], str): - control = args.pop(0) - elif "c" in kwargs: - control = kwargs.pop("c") - - if len(args) > 0 and (args[0] is None or isinstance(args[0], QWidget)): - parent = args[0] - elif "parent" in kwargs: - parent = kwargs["parent"] - - if len(args) > 1: - window_flags = args[1] - elif "f" in kwargs: - window_flags = kwargs["f"] - - if control is None: - control = self.CLSID - - # Call super inits - QWidgetLogging.__init__(self, *args, **kwargs) - KiwoomOpenApiWQAxWidgetMixin.__init__(self) - - # Create QAxWidget - self._control = control - self._ax = QAxWidget(self._control, self) - - # Check if instantiation of the QAxWidget was successful - successful = not self._ax.isNull() - if not successful: - raise RuntimeError( - "Requested control {} could not be instantiated".format(self._control) - ) - - # Set methods as attributes - for method_name in self.METHOD_NAMES: - dynamic_callable = KiwoomOpenApiWDynamicCallable(self._ax, method_name) - setattr(self, method_name, dynamic_callable) - - # Set signals as attributes - for event_name in self.EVENT_NAMES: - signal_connector = KiwoomOpenApiWSignalConnector(event_name) - signal_connector.connect_to(self._ax) - setattr(self, event_name, signal_connector) - - # Enable logging for QAxWidget exceptions - self._ax.exception.connect(self._onException) # pylint: disable=no-member - - # Enable logging for OpenAPI events - self._event_logger = KiwoomOpenApiWLoggingEventHandler(self) - self._event_logger.connect() - - def _onException( - self, code, source, desc, help - ): # pylint: disable=redefined-builtin - self.logger.error("QAxBaseException(%r, %r, %r, %r)", code, source, desc, help) - - def __getattr__(self, name): - try: - return getattr(self._ax, name) - except AttributeError as e: - raise AttributeError( - "'{}' object has no attribute '{}'".format( - self.__class__.__name__, name - ) - ) from e - - def changeEvent(self, event): - if event.type() == QEvent.WindowStateChange: - if self.windowState() & Qt.WindowMinimized: - event.accept() - - def closeEvent(self, event): - self.hide() - event.ignore() diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.py deleted file mode 100644 index 69b37e53..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin.py +++ /dev/null @@ -1,3 +0,0 @@ -class KiwoomOpenApiWQAxWidgetMixin: - - pass diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.py deleted file mode 100644 index a85d8b3b..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector.py +++ /dev/null @@ -1,66 +0,0 @@ -import inspect -import threading - -from koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature import ( - KiwoomOpenApiWEventHandlerSignature, -) -from koapy.compat.pyside2 import PYQT5, PYSIDE2, PythonQtError -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiWSignalConnector(Logging): - def __init__(self, name=None): - super().__init__() - - self._name = name - self._lock = threading.RLock() - self._slots = list() - - self._signature = KiwoomOpenApiWEventHandlerSignature.from_name(self._name) - self._param_types = [ - (p.annotation) for p in self._signature.parameters.values() - ] - self._signal = self._signature.to_pyside2_event_signal() - - def is_valid_slot(self, slot): - slot_signature = inspect.signature(slot) - slot_types = [(p.annotation) for p in slot_signature.parameters.values()] - condition = len(self._param_types) == len( - slot_types - ) # currently only check parameter length - return condition - - def connect_to(self, control): - if PYSIDE2: - return control.connect(self._signal, self) - elif PYQT5: - return getattr(control, self._name).connect(self) - else: - raise PythonQtError("Unsupported Qt bindings") - - def connect(self, slot): - if not self.is_valid_slot(slot): - raise TypeError("Invalid slot: %s" % slot) - with self._lock: - if slot not in self._slots: - self._slots.append(slot) - - def disconnect(self, slot=None): - with self._lock: - if slot is None: - self._slots.clear() - elif slot in self._slots: - self._slots.remove(slot) - else: - self.logger.warning("Tried to disconnect a slot that doesn't exist") - - def call(self, *args, **kwargs): - # make a copy in order to prevent modification during iteration problem - with self._lock: - slots = list(self._slots) - # TODO: use Thread with await/join for concurrency? - for slot in slots: - slot(*args, **kwargs) - - def __call__(self, *args, **kwargs): - return self.call(*args, **kwargs) diff --git a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.py b/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.py deleted file mode 100644 index ca2d1e68..00000000 --- a/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature.py +++ /dev/null @@ -1,185 +0,0 @@ -from collections import OrderedDict -from inspect import Parameter, Signature - -import pythoncom - -from win32com.client import genpy, selecttlb - -from koapy.compat.pyside2.QtCore import SIGNAL - - -def BuildOleItems(clsid): - tlbs = selecttlb.EnumTlbs() - tlbs = {tlb.clsid: tlb for tlb in tlbs} - - tlbSpec = tlbs.get(clsid) - - if tlbSpec is None: - return {} # raise LookupError('KHOpenAPI Module not found') - - if tlbSpec.dll is None: - tlb = pythoncom.LoadRegTypeLib( - tlbSpec.clsid, int(tlbSpec.major, 16), int(tlbSpec.minor, 16), tlbSpec.lcid - ) - else: - tlb = pythoncom.LoadTypeLib(tlbSpec.dll) - - gen = genpy.Generator(tlb, tlbSpec.dll, None, bBuildHidden=1) - oleItems, _enumItems, _recordItems, _vtableItems = gen.BuildOleItemsFromType() - - oleItems = {str(clsId): oleItem for clsId, oleItem in oleItems.items()} - - return oleItems - - -class KiwoomOpenApiWSignature(Signature): - - MODULE_CLSID = "{1F8A15ED-A979-488F-9694-1EDA98188FFC}" - - OLE_ITEMS = BuildOleItems(MODULE_CLSID) - - DISPATCH_CLSID = "{85B07632-4F84-4CEF-991D-C79DE781363D}" - EVENT_CLSID = "{952B31F8-06FD-4D5A-A021-5FF57F5030AE}" - - PYTHONTYPE_TO_QTTYPE = { - int: "int", - str: "const QString&", - } - - COMTYPE_TO_PYTHONTYPE = { - pythoncom.VT_I4: int, - pythoncom.VT_BSTR: str, - pythoncom.VT_VARIANT: type( - None - ), # QVariant does not exist in PySide2 (Currently PyQt5 only) - pythoncom.VT_VOID: type(None), - } - - def __init__( - self, name, parameters=None, return_annotation=Signature.empty, entry=None - ): - self._name = name - self._entry = entry - super().__init__(parameters, return_annotation=return_annotation) - - @property - def name(self): - return self._name - - @classmethod - def _pythontype_to_qttype(cls, typ): - return cls.PYTHONTYPE_TO_QTTYPE[typ] - - def to_pyside2_function_prototype(self): - name = self._name - parameters = self.parameters - parameters = parameters.values() - parameters = [self._pythontype_to_qttype(p.annotation) for p in parameters] - prototype = "{}({})".format(name, ", ".join(parameters)) - return prototype - - def to_pyside2_event_signal(self): - return SIGNAL(self.to_pyside2_function_prototype()) - - @classmethod - def _comtype_to_pythontype(cls, typ): - return cls.COMTYPE_TO_PYTHONTYPE[typ] - - @classmethod - def _from_entry(cls, name, entry): - arg_names = entry.names[1:] - arg_types = [typ[0] for typ in entry.desc[2]] - return_type = entry.desc[8][0] - parameters = [ - Parameter( - name=arg_name, - kind=Parameter.POSITIONAL_OR_KEYWORD, - annotation=cls._comtype_to_pythontype(arg_type), - ) - for arg_name, arg_type in zip(arg_names, arg_types) - ] - return_annotation = cls._comtype_to_pythontype(return_type) - signature = cls( - name=name, - parameters=parameters, - return_annotation=return_annotation, - entry=entry, - ) - return signature - - -class KiwoomOpenApiWDispatchSignature(KiwoomOpenApiWSignature): - - DISPATCH_SIGNATURES_BY_NAME = {} - - @classmethod - def from_name(cls, name): - return cls.DISPATCH_SIGNATURES_BY_NAME[name] - - @classmethod - def names(cls): - return list(cls.DISPATCH_SIGNATURES_BY_NAME.keys()) - - -def LoadDispatchSignatures(oleItems, clsId): - if clsId not in oleItems: - return {} - dispatch = oleItems[clsId] - dispatch_funcs = [ - (name, entry) - for name, entry in dispatch.mapFuncs.items() - if not any( - [ - entry.desc[9] & pythoncom.FUNCFLAG_FRESTRICTED - and entry.desc[0] != pythoncom.DISPID_NEWENUM, - entry.desc[3] != pythoncom.FUNC_DISPATCH, - entry.desc[0] == pythoncom.DISPID_NEWENUM, - ] - ) - ] - dispatch_signatures_by_name = OrderedDict() - for func_name, entry in dispatch_funcs: - signature = KiwoomOpenApiWDispatchSignature._from_entry( - func_name, entry - ) # pylint: disable=protected-access - dispatch_signatures_by_name[func_name] = signature - return dispatch_signatures_by_name - - -KiwoomOpenApiWDispatchSignature.DISPATCH_SIGNATURES_BY_NAME = LoadDispatchSignatures( - KiwoomOpenApiWSignature.OLE_ITEMS, KiwoomOpenApiWSignature.DISPATCH_CLSID -) - - -class KiwoomOpenApiWEventHandlerSignature(KiwoomOpenApiWSignature): - - EVENT_HANDLER_SIGNATURES_BY_NAME = {} - - @classmethod - def from_name(cls, name): - return cls.EVENT_HANDLER_SIGNATURES_BY_NAME[name] - - @classmethod - def names(cls): - return list(cls.EVENT_HANDLER_SIGNATURES_BY_NAME.keys()) - - -def LoadEventHandlerSignatures(oleItems, clsId): - if clsId not in oleItems: - return {} - event = oleItems[clsId] - event_funcs = event.mapFuncs.items() - event_handler_signatures_by_name = OrderedDict() - for func_name, entry in event_funcs: - signature = KiwoomOpenApiWEventHandlerSignature._from_entry( - func_name, entry - ) # pylint: disable=protected-access - event_handler_signatures_by_name[func_name] = signature - return event_handler_signatures_by_name - - -KiwoomOpenApiWEventHandlerSignature.EVENT_HANDLER_SIGNATURES_BY_NAME = ( - LoadEventHandlerSignatures( - KiwoomOpenApiWSignature.OLE_ITEMS, KiwoomOpenApiWSignature.EVENT_CLSID - ) -) diff --git a/koapy/backend/kiwoom_open_api_w/core/__init__.py b/koapy/backend/kiwoom_open_api_w/core/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backtrader/KiwoomOpenApiPlusBroker.py b/koapy/backtrader/KiwoomOpenApiPlusBroker.py deleted file mode 100644 index d2fbf7da..00000000 --- a/koapy/backtrader/KiwoomOpenApiPlusBroker.py +++ /dev/null @@ -1,436 +0,0 @@ -import collections - -from backtrader import BrokerBase, BuyOrder, Order, SellOrder -from backtrader.comminfo import CommInfoBase -from backtrader.position import Position -from backtrader.utils.py3 import with_metaclass - -from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore - - -class KiwoomOpenApiPlusCommInfo(CommInfoBase): - - # pylint: disable=no-member - - params = ( - ("stocklike", True), - ("commtype", CommInfoBase.COMM_PERC), - ("percabs", False), - ("commission", 0.015), - ("tax", 0.25), - ("mult", 1.0), - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - if self._commtype == self.COMM_PERC and not self.p.percabs: - self.p.tax /= 100.0 - - def _getcommissionbuy(self, size, price, pseudoexec): - return size * price * self.p.commission * self.p.mult - - def _getcommissionsell(self, size, price, pseudoexec): - return abs(size) * price * (self.p.commission + self.p.tax) * self.p.mult - - def _getcommission(self, size, price, pseudoexec): - if size < 0: - return self._getcommissionsell(size, price, pseudoexec) - else: - return self._getcommissionbuy(size, price, pseudoexec) - - -class MetaKiwoomOpenApiPlusBroker(BrokerBase.__class__): - def __init__(cls, name, bases, dct): - super().__init__(name, bases, dct) - KiwoomOpenApiPlusStore.BrokerCls = cls - - -class KiwoomOpenApiPlusBroker(with_metaclass(MetaKiwoomOpenApiPlusBroker, BrokerBase)): - - params = ( - ("use_positions", True), - ("commission", KiwoomOpenApiPlusCommInfo()), - ) - - _store = KiwoomOpenApiPlusStore - - def __init__(self, *args, **kwargs): - super().__init__() - - self.k = self._store(*args, **kwargs) - - self.orders = collections.OrderedDict() # orders by order id - self.notifs = collections.deque() # holds orders which are notified - - self.opending = collections.defaultdict(list) # pending transmission - self.brackets = dict() # confirmed brackets - - self.startingcash = self.cash = 0.0 - self.startingvalue = self.value = 0.0 - self.positions = collections.defaultdict(Position) - - def start(self): - super().start() - self.k.start(broker=self) - self.startingcash = self.cash = self.k.get_cash() - self.startingvalue = self.value = self.k.get_value() - - if self.p.use_positions: # pylint: disable=no-member - for p in self.k.get_positions(): - is_sell = p["side"] == "sell" - size = p["units"] - if is_sell: - size = -size - price = p["avgPrice"] - self.positions[p["instrument"]] = Position(size, price) - - def data_started(self, data): - pos = self.getposition(data) - - if pos.size < 0: - # pylint: disable=unexpected-keyword-arg - order = SellOrder( - data=data, - size=pos.size, - price=pos.price, - exectype=Order.Market, - simulated=True, - ) - - order.addcomminfo(self.getcommissioninfo(data)) - order.execute( - 0, - pos.size, - pos.price, - 0, - 0.0, - 0.0, - pos.size, - 0.0, - 0.0, - 0.0, - 0.0, - pos.size, - pos.price, - ) - - order.completed() - self.notify(order) - - elif pos.size > 0: - # pylint: disable=unexpected-keyword-arg - order = BuyOrder( - data=data, - size=pos.size, - price=pos.price, - exectype=Order.Market, - simulated=True, - ) - - order.addcomminfo(self.getcommissioninfo(data)) - order.execute( - 0, - pos.size, - pos.price, - 0, - 0.0, - 0.0, - pos.size, - 0.0, - 0.0, - 0.0, - 0.0, - pos.size, - pos.price, - ) - - order.completed() - self.notify(order) - - def stop(self): - super().stop() - self.k.stop() - - def getcash(self): - self.cash = self.k.get_cash() - return self.cash - - def getvalue(self, datas=None): - self.value = self.k.get_value() - return self.value - - def getposition(self, data, clone=True): # pylint: disable=arguments-differ - pos = self.positions[data._dataname] # pylint: disable=protected-access - if clone: - pos = pos.clone() - return pos - - def orderstatus(self, order): - order = self.orders[order.ref] - return order.status - - def _submit(self, oref): - order = self.orders[oref] - order.submit(self) - self.notify(order) - for o in self._bracketnotif(order): - o.submit(self) - self.notify(o) - - def _reject(self, oref): - order = self.orders[oref] - order.reject(self) - self.notify(order) - self._bracketize(order, cancel=True) - - def _accept(self, oref): - order = self.orders[oref] - order.accept() - self.notify(order) - for o in self._bracketnotif(order): - o.accept(self) - self.notify(o) - - def _cancel(self, oref): - order = self.orders[oref] - order.cancel() - self.notify(order) - self._bracketize(order, cancel=True) - - def _expire(self, oref): - order = self.orders[oref] - order.expire() - self.notify(order) - self._bracketize(order, cancel=True) - - def _bracketnotif(self, order): - pref = getattr(order.parent, "ref", order.ref) # parent ref or self - br = self.brackets.get(pref, None) # to avoid recursion - return br[-2:] if br is not None else [] - - def _bracketize(self, order, cancel=False): - pref = getattr(order.parent, "ref", order.ref) # parent ref or self - br = self.brackets.pop(pref, None) # to avoid recursion - if br is None: - return - - if not cancel: - if len(br) == 3: # all 3 orders in place, parent was filled - br = br[1:] # discard index 0, parent - for o in br: - o.activate() # simulate activate for children - self.brackets[pref] = br # not done - reinsert children - - elif len(br) == 2: # filling a children - oidx = br.index(order) # find index to filled (0 or 1) - self._cancel(br[1 - oidx].ref) # cancel remaining (1 - 0 -> 1) - else: - # Any cancellation cancel the others - for o in br: - if o.alive(): - self._cancel(o.ref) - - def _fill(self, oref, size, price, ttype, **kwargs): - order = self.orders[oref] - - if not order.alive(): # can be a bracket - pref = getattr(order.parent, "ref", order.ref) - if pref not in self.brackets: - msg = ( - "Order fill received for {}, with price {} and size {} " - "but order is no longer alive and is not a bracket. " - "Unknown situation" - ) - msg.format(order.ref, price, size) - self.put_notification( - msg, order, price, size - ) # pylint: disable=no-member - return - - # [main, stopside, takeside], neg idx to array are -3, -2, -1 - if ttype == "STOP_LOSS_FILLED": - order = self.brackets[pref][-2] - elif ttype == "TAKE_PROFIT_FILLED": - order = self.brackets[pref][-1] - else: - msg = ( - "Order fill received for {}, with price {} and size {} " - "but order is no longer alive and is a bracket. " - "Unknown situation" - ) - msg.format(order.ref, price, size) - self.put_notification( - msg, order, price, size - ) # pylint: disable=no-member - return - - data = order.data - pos = self.getposition(data, clone=False) - psize, pprice, opened, closed = pos.update(size, price) - - comminfo = self.getcommissioninfo(data) # pylint: disable=unused-variable - - closedvalue = closedcomm = 0.0 - openedvalue = openedcomm = 0.0 - margin = pnl = 0.0 - - if size >= 0: - openedvalue = comminfo.getvaluesize(size, price) - openedcomm = comminfo.confirmexec(size, price) - else: - closedvalue = comminfo.getvaluesize(size, price) - closedcomm = comminfo.confirmexec(size, price) - - order.execute( - data.datetime[0], - size, - price, - closed, - closedvalue, - closedcomm, - opened, - openedvalue, - openedcomm, - margin, - pnl, - psize, - pprice, - ) - - if order.executed.remsize: - order.partial() - self.notify(order) - else: - order.completed() - self.notify(order) - self._bracketize(order) - - def _transmit(self, order): - oref = order.ref - pref = getattr(order.parent, "ref", oref) # parent ref or self - - if order.transmit: - if oref != pref: # children order - # Put parent in orders dict, but add stopside and takeside - # to order creation. Return the takeside order, to have 3s - takeside = order # alias for clarity - parent, stopside = self.opending.pop(pref) - for o in parent, stopside, takeside: - self.orders[o.ref] = o # write them down - - self.brackets[pref] = [parent, stopside, takeside] - self.k.order_create(parent, stopside, takeside) - return takeside # parent was already returned - - else: # Parent order, which is not being transmitted - self.orders[order.ref] = order - return self.k.order_create(order) - - # Not transmitting - self.opending[pref].append(order) - return order - - def buy( - self, - owner, - data, - size, - price=None, - plimit=None, - exectype=None, - valid=None, - tradeid=0, - oco=None, - trailamount=None, - trailpercent=None, - parent=None, - transmit=True, - **kwargs - ): # pylint: disable=arguments-differ - - # pylint: disable=unexpected-keyword-arg - order = BuyOrder( - owner=owner, - data=data, - size=size, - price=price, - pricelimit=plimit, - exectype=exectype, - valid=valid, - tradeid=tradeid, - trailamount=trailamount, - trailpercent=trailpercent, - parent=parent, - transmit=transmit, - ) - - order.addinfo(**kwargs) - order.addcomminfo(self.getcommissioninfo(data)) - return self._transmit(order) - - def sell( - self, - owner, - data, - size, - price=None, - plimit=None, - exectype=None, - valid=None, - tradeid=0, - oco=None, - trailamount=None, - trailpercent=None, - parent=None, - transmit=True, - **kwargs - ): # pylint: disable=arguments-differ - - # pylint: disable=unexpected-keyword-arg - order = SellOrder( - owner=owner, - data=data, - size=size, - price=price, - pricelimit=plimit, - exectype=exectype, - valid=valid, - tradeid=tradeid, - trailamount=trailamount, - trailpercent=trailpercent, - parent=parent, - transmit=transmit, - ) - - order.addinfo(**kwargs) - order.addcomminfo(self.getcommissioninfo(data)) - return self._transmit(order) - - def cancel(self, order): - order = self.orders[order.ref] - if order.status == Order.Cancelled: - return - return self.k.order_cancel(order) - - def notify(self, order): - self.notifs.append(order.clone()) - - def get_notification(self): - if not self.notifs: - return None - return self.notifs.popleft() - - def next(self): - self.notifs.append(None) - - # below may not accurate - - def submit(self, order): - return self._transmit(order) - - def add_order_history(self, orders, notify=False): - return self.k.add_order_history(orders, notify) - - def set_fund_history(self, fund): - return self.k.set_fund_history(fund) diff --git a/koapy/backtrader/KiwoomOpenApiPlusData.py b/koapy/backtrader/KiwoomOpenApiPlusData.py deleted file mode 100644 index 562ba031..00000000 --- a/koapy/backtrader/KiwoomOpenApiPlusData.py +++ /dev/null @@ -1,365 +0,0 @@ -import datetime - -from backtrader import date2num, num2date -from backtrader.feed import DataBase -from backtrader.utils.py3 import queue -from pytz import utc - -from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore -from koapy.utils.logging.Logging import Logging - - -class MetaKiwoomOpenApiPlusData(type(Logging), type(DataBase)): - def __init__(cls, clsname, bases, dct): - super().__init__(clsname, bases, dct) - KiwoomOpenApiPlusStore.DataCls = cls - - -class KiwoomOpenApiPlusData(DataBase, Logging, metaclass=MetaKiwoomOpenApiPlusData): - - # pylint: disable=no-member - - params = ( - ("qcheck", 0.5), - ("historical", False), # do backfilling at the start - ("backfill_start", True), # do backfilling at the start - ("backfill", True), # do backfilling when reconnecting - ("backfill_from", None), # additional data source to do backfill from - ("useask", False), - ("reconnect", True), - ("reconnections", -1), # forever - ("reconntimeout", 5.0), - ("tz", "Asia/Seoul"), - ( - "tzinput", - None, - ), # this should be none (utc) since we are already putting datetimes converted to utc - ("calendar", None), - ) - - _store = KiwoomOpenApiPlusStore - - _ST_FROM, _ST_START, _ST_LIVE, _ST_HISTORBACK, _ST_OVER = range(5) - - def __init__(self, *args, **kwargs): - self.k = self._store(*args, **kwargs) - - if self.p.dataname not in self.k.datanames: - self.k.datanames.append(self.p.dataname) - - self.qlive = queue.Queue() - self.qhist = queue.Queue() - - self.contractdetails = None - - self._statelivereconn = False - self._storedmsg = dict() - self._state = self._ST_OVER - self._reconns = 0 - - self._tz = self._gettz() - - def _timeoffset(self): - return self.k.timeoffset() - - def isnaive(self, dt): - return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None - - def asutc(self, dt, tz=None, naive=True): - if tz is None: - tz = self._tz - if self.isnaive(dt) and tz is not None: - dt = tz.localize(dt) - dt = dt.astimezone(utc) - if naive: - dt = dt.replace(tzinfo=None) - return dt - - def date2num(self, dt, tz=None): # pylint: disable=arguments-differ - dt = self.asutc(dt, tz) - return date2num(dt) - - def num2date(self, dt=None, tz=None, naive=False): - if dt is None: - dt = self.lines.datetime[0] - if tz is None: - tz = self._tz - return num2date(dt, tz, naive) - - def fromtimestamp(self, timestamp, tz=None): - if tz is None: - tz = self._tz - return datetime.datetime.fromtimestamp(timestamp, tz=tz) - - def islive(self): - return not self.p.historical - - def setenvironment(self, env): - super().setenvironment(env) - env.addstore(self.k) - - def start(self): - super().start() - - self.qlive = queue.Queue() - self.qhist = queue.Queue() - - self._statelivereconn = False - self._storedmsg = dict() - self._state = self._ST_OVER - - self.k.start(data=self) - - otf = self.k.get_granularity(self.p.timeframe, self.p.compression) - - if otf is None: - self.logger.warning( - "Given timeframe and compression not supported: (%s, %s)", - self.p.timeframe, - self.p.compression, - ) - self.put_notification(self.NOTSUPPORTED_TF) - self._state = self._ST_OVER - return - - self.contractdetails = cd = self.k.get_instrument(self.p.dataname) - - if cd is None: - self.logger.warning("Given dataname is not supported") - self.put_notification(self.NOTSUBSCRIBED) - self._state = self._ST_OVER - return - - if self.p.backfill_from is not None: - self._state = self._ST_FROM - self.p.backfill_from.setenvironment(self._env) - self.p.backfill_from._start() # pylint: disable=protected-access - else: - self._start_finish() - self._state = self._ST_START - self._st_start() - - self._reconns = 0 - - def _st_start(self, instart=True, tmout=None): - if self.p.historical: - self.put_notification(self.DELAYED) - - dtend = None - if self.todate < float("inf"): - dtend = self.num2date(self.todate) - - dtbegin = None - if self.fromdate > float("-inf"): - dtbegin = self.num2date(self.fromdate) - - self.qhist = self.k.candles( - self.p.dataname, dtbegin, dtend, self.p.timeframe, self.p.compression - ) - - self._state = self._ST_HISTORBACK - - return True - else: - self.qlive = self.k.streaming_prices(self.p.dataname, tmout=tmout) - - if instart: - self._statelivereconn = self.p.backfill_start - else: - self._statelivereconn = self.p.backfill - - if self._statelivereconn: - self.put_notification(self.DELAYED) - - self._state = self._ST_LIVE - - if instart: - self._reconns = self.p.reconnections - - if instart and not self.p.backfill_start: - self.put_notification(self.DELAYED) - - msg = self.k.initial_today_historical_msg(data=self) - - self.qhist.put(msg) - self.qhist.put({}) - - self._state = self._ST_HISTORBACK - - return True - - def stop(self): - super().stop() - self.k.stop() - - def haslivedata(self): - return bool(self._storedmsg or not self.qlive.empty()) - - def _load(self): - if self._state == self._ST_OVER: - return False - - while True: - if self._state == self._ST_LIVE: - try: - msg = self._storedmsg.pop(None, None) or self.qlive.get( - timeout=self._qcheck - ) - except queue.Empty: - return None - - if msg is None: - self.put_notification(self.CONNBROKEN) - - if not self.p.reconnect or self._reconns == 0: - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - self._reconns -= 1 - self._st_start(instart=False, tmout=self.p.reconntimeout) - continue - - if "code" in msg: - self.put_notification(self.CONNBROKEN) - - code = msg["code"] - - if code not in [599, 598, 596]: - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - if not self.p.reconnect or self._reconns == 0: - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - self._reconns -= 1 - self._st_start(instart=False, tmout=self.p.reconntimeout) - continue - - self._reconns = self.p.reconnections - - if not self._statelivereconn: - if self._laststatus != self.LIVE: - if self.qlive.qsize() <= 1: - self.put_notification(self.LIVE) - - ret = self._load_tick(msg) - if ret: - return True - continue - - self._storedmsg[None] = msg - - if self._laststatus != self.DELAYED: - self.put_notification(self.DELAYED) - - dtend = None - if len(self) > 1: - dtbegin = self.datetime.datetime(-1) - elif self.fromdate > float("-inf"): - dtbegin = self.num2date(self.fromdate) - else: - dtbegin = None - - dtend = self.fromtimestamp(int(msg["time"]) / 10**6) - - self.qhist = self.k.candles( - self.p.dataname, - dtbegin, - dtend, - self.p.timeframe, - self.p.compression, - ) - - self._state = self._ST_HISTORBACK - self._statelivereconn = False - continue - - elif self._state == self._ST_HISTORBACK: - msg = self.qhist.get() - if msg is None: - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - elif "code" in msg: - self.put_notification(self.NOTSUBSCRIBED) - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - if msg: - if self._load_history(msg): - return True - continue - else: - if self.p.historical: - self.put_notification(self.DISCONNECTED) - self._state = self._ST_OVER - return False - - self._state = self._ST_LIVE - continue - - elif self._state == self._ST_FROM: - if not self.p.backfill_from.next(): - self._state = self._ST_START - continue - - # copy lines of the same name - for alias in self.lines.getlinealiases(): - lsrc = getattr(self.p.backfill_from.lines, alias) - ldst = getattr(self.lines, alias) - - ldst[0] = lsrc[0] - - return True - - elif self._state == self._ST_START: - if not self._st_start(instart=False): - self._state = self._ST_OVER - return False - - def _load_tick(self, msg): - dtobj = self.fromtimestamp(int(msg["time"]) / 10**6) - dt = self.date2num(dtobj) - if dt <= self.lines.datetime[-1]: - return False # time already seen - - # Common fields - self.lines.datetime[0] = dt - self.lines.volume[0] = 0.0 - self.lines.openinterest[0] = 0.0 - - # Put the prices into the bar - tick = float(msg["ask"]) if self.p.useask else float(msg["bid"]) - self.lines.open[0] = tick - self.lines.high[0] = tick - self.lines.low[0] = tick - self.lines.close[0] = tick - self.lines.volume[0] = 0.0 - self.lines.openinterest[0] = 0.0 - - return True - - def _load_history(self, msg): - dtobj = self.fromtimestamp(int(msg["time"]) / 10**6) - dt = self.date2num(dtobj) - if dt <= self.lines.datetime[-1]: - return False # time already seen - - # Common fields - self.lines.datetime[0] = dt - self.lines.volume[0] = float(msg["volume"]) - self.lines.openinterest[0] = 0.0 - - # Put the prices into the bar - self.lines.open[0] = float(msg["open"]) - self.lines.high[0] = float(msg["high"]) - self.lines.low[0] = float(msg["low"]) - self.lines.close[0] = float(msg["close"]) - - return True diff --git a/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.py b/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.py deleted file mode 100644 index 0641dce9..00000000 --- a/koapy/backtrader/KiwoomOpenApiPlusEventStreamer.py +++ /dev/null @@ -1,322 +0,0 @@ -import datetime -import threading - -import rx - -from exchange_calendars import get_calendar -from rx import operators as ops -from rx.core.typing import Observer -from rx.scheduler import ThreadPoolScheduler -from rx.subject import Subject - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, -) -from koapy.backend.kiwoom_open_api_plus.grpc import KiwoomOpenApiPlusService_pb2 -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator import ( - QueueBasedBufferedIterator, -) -from koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver import ( - QueueBasedIterableObserver, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusPriceEventChannel(Logging): - - _krx_timezone = get_calendar("XKRX").tz - - def __init__(self, stub): - self._stub = stub - self._fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") - - self._request_observer = QueueBasedIterableObserver() - self._request_iterator = iter(self._request_observer) - self._response_iterator = self._stub.BidirectionalRealCall( - self._request_iterator - ) - self._response_subject = Subject() - self._response_scheduler_max_workers = 8 - self._response_scheduler = ThreadPoolScheduler( - self._response_scheduler_max_workers - ) - self._buffered_response_iterator = QueueBasedBufferedIterator( - self._response_iterator - ) - self._response_observable = rx.from_iterable( - self._buffered_response_iterator, self._response_scheduler - ) - self._response_subscription = self._response_observable.subscribe( - self._response_subject - ) - - self._subjects_by_code = {} - - self.initialize() - - def close(self): - for _code, (_subject, subscription) in self._subjects_by_code.items(): - subscription.dispose() - self._response_subscription.dispose() - self._buffered_response_iterator.stop() - self._response_iterator.cancel() - - def __del__(self): - self.close() - - def initialize(self): - request = KiwoomOpenApiPlusService_pb2.BidirectionalRealRequest() - request.initialize_request.fid_list.extend( - self._fid_list - ) # pylint: disable=no-member - self._request_observer.on_next(request) - - def register_code(self, code): - request = KiwoomOpenApiPlusService_pb2.BidirectionalRealRequest() - code_list = [code] - fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") - request.register_request.code_list.extend( - code_list - ) # pylint: disable=no-member - request.register_request.fid_list.extend(fid_list) # pylint: disable=no-member - self._request_observer.on_next(request) - self.logger.debug("Registering code %s for real events", code) - - def is_for_code(self, response, code): - return response.arguments[0].string_value == code - - def filter_for_code(self, code): - return ops.filter(lambda response: self.is_for_code(response, code)) - - def is_valid_price_event(self, response): - return all(name in response.single_data.names for name in ["20", "27", "28"]) - - def filter_price_event(self): - return ops.filter(self.is_valid_price_event) - - def time_to_timestamp(self, fid20): - dt = datetime.datetime.now(self._krx_timezone).date() - tm = datetime.datetime.strptime(fid20, "%H%M%S").time() - dt = datetime.datetime.combine(dt, tm) - dt = self._krx_timezone.localize(dt) - return dt.timestamp() * (10**6) - - def event_to_dict(self, response): - single_data = dict(zip(response.single_data.names, response.single_data.values)) - result = { - "time": self.time_to_timestamp(single_data["20"]), - "bid": abs(float(single_data["28"])), - "ask": abs(float(single_data["27"])), - } - return result - - def convert_to_dict(self): - return ops.map(self.event_to_dict) - - def get_observable_for_code(self, code): - self.register_code(code) - if code not in self._subjects_by_code: - subject = Subject() - subscription = self._response_subject.pipe( - self.filter_for_code(code), - self.filter_price_event(), - self.convert_to_dict(), - ).subscribe(subject) - self._subjects_by_code[code] = (subject, subscription) - subject, subscription = self._subjects_by_code[code] - return subject - - -class KiwoomOpenApiPlusOrderEventChannel: - def __init__(self, stub): - self._stub = stub - - request = KiwoomOpenApiPlusService_pb2.ListenRequest() - self._response_iterator = self._stub.OrderListen(request) - self._response_subject = Subject() - self._response_scheduler_max_workers = 8 - self._response_scheduler = ThreadPoolScheduler( - self._response_scheduler_max_workers - ) - self._buffered_response_iterator = QueueBasedBufferedIterator( - self._response_iterator - ) - self._response_observable = rx.from_iterable( - self._buffered_response_iterator, self._response_scheduler - ) - self._response_subscription = self._response_observable.subscribe( - self._response_subject - ) - - self._observable = Subject() - self._subscription = self._response_subject.pipe( - self.filter_chejan_response(), - self.convert_to_dict(), - ).subscribe(self._observable) - - def close(self): - self._subscription.dispose() - self._response_subscription.dispose() - self._buffered_response_iterator.stop() - self._response_iterator.cancel() - - def __del__(self): - self.close() - - def is_chejan_response(self, response): - name = response.name - gubun = response.arguments[0].string_value - if name == "OnReceiveChejanData" and gubun == "0": - data = dict(zip(response.single_data.names, response.single_data.values)) - order_type = data["주문구분"] - hoga_type = data["매매구분"] - status = data["주문상태"] - market_order_created_and_filled = ( - order_type in ["+매수", "-매도"] - and hoga_type in ["시장가"] - and status in ["체결"] - ) - limit_order_created = ( - order_type in ["+매수", "-매도"] - and hoga_type in ["보통"] - and status in ["접수"] - and data["819"] in ["0"] - ) # 취소 확인 뒤에 오는 원주문 이벤트는 819 가 1 로 들어오는 것 같음 - order_filled = order_type in ["+매수", "-매도"] and status in ["체결"] - order_canceled = order_type in ["매수취소", "매도취소"] and status in ["확인"] - condition = any( - [ - market_order_created_and_filled, - limit_order_created, - order_filled, - order_canceled, - ] - ) - return condition - return False - - def filter_chejan_response(self): - return ops.filter(self.is_chejan_response) - - def event_to_dict(self, response): - result = {} - data = dict(zip(response.single_data.names, response.single_data.values)) - original_order_no = data["원주문번호"] - if int(original_order_no): - status = data["주문상태"] - if status == "확인": - reject_reason = data["거부사유"] - result = { - "type": "ORDER_CANCEL", - "orderId": original_order_no, - "reason": reject_reason if int(reject_reason) else "ORDER_FILLED", - } - else: - status = data["주문상태"] - hoga_type = data["매매구분"] - if status == "접수": - if hoga_type == "보통": - order_no = data["주문번호"] - result = { - "type": "LIMIT_ORDER_CREATE", - "id": order_no, - } - elif hoga_type == "시장가": - pass - else: - self.logger.warning("Unexpected hoga type %s", hoga_type) - elif status == "체결": - if hoga_type == "보통": - order_no = data["주문번호"] - units = data["단위체결량"] - buy_or_sell = data["주문구분"] - side = { - "+매수": "buy", - "-매도": "sell", - }[buy_or_sell] - price = data["단위체결가"] - result = { - "type": "ORDER_FILLED", - "orderId": order_no, - "units": int(units), - "side": side, - "price": abs(float(price)), - } - elif hoga_type == "시장가": - order_no = data["주문번호"] - units = data["단위체결량"] - buy_or_sell = data["주문구분"] - side = { - "+매수": "buy", - "-매도": "sell", - }[buy_or_sell] - price = data["단위체결가"] - result = { - "type": "MARKET_ORDER_CREATE", - "id": order_no, - "tradeOpened": {"id": order_no}, - "units": int(units), - "side": side, - "price": abs(float(price)), - } - else: - self.logger.warning("Unexpected hoga type %s", hoga_type) - else: - self.logger.warning("Unexcpected status %s", status) - return result - - def convert_to_dict(self): - return ops.map(self.event_to_dict) - - def get_observable(self): - return self._observable - - -class MetaKiwoomOpenApiPlusEventStreamer(type(Logging), type(Observer)): - pass - - -class KiwoomOpenApiPlusEventStreamer( - Observer, Logging, metaclass=MetaKiwoomOpenApiPlusEventStreamer -): - - _price_event_channels_by_stub = {} - _order_event_channels_by_stub = {} - - _lock = threading.RLock() - - def __init__(self, stub, queue): - super().__init__() - self._stub = stub - self._queue = queue - - def on_next(self, value): - self._queue.put(value) - - def on_error(self, error): - self.logger.error("Streamer.on_error(%s)", error) - - def on_completed(self): - pass - - def rates(self, code): - with self._lock: - if self._stub not in self._price_event_channels_by_stub: - self._price_event_channels_by_stub[ - self._stub - ] = KiwoomOpenApiPlusPriceEventChannel(self._stub) - event_channel = self._price_event_channels_by_stub[self._stub] - subscription = event_channel.get_observable_for_code(code).subscribe(self) - self.logger.debug("Subscribing rates for code %s", code) - return subscription - - def events(self): - with self._lock: - if self._stub not in self._order_event_channels_by_stub: - self._order_event_channels_by_stub[ - self._stub - ] = KiwoomOpenApiPlusOrderEventChannel(self._stub) - event_channel = self._order_event_channels_by_stub[self._stub] - subscription = event_channel.get_observable().subscribe(self) - self.logger.debug("Subscribing order events") - return subscription diff --git a/koapy/backtrader/KiwoomOpenApiPlusStore.py b/koapy/backtrader/KiwoomOpenApiPlusStore.py deleted file mode 100644 index 4c703f0e..00000000 --- a/koapy/backtrader/KiwoomOpenApiPlusStore.py +++ /dev/null @@ -1,809 +0,0 @@ -import collections -import datetime -import threading -import time - -import backtrader as bt -import numpy as np -import pandas as pd - -from backtrader import TimeFrame -from backtrader.metabase import MetaParams -from backtrader.utils.py3 import queue -from exchange_calendars import get_calendar - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, -) -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - KiwoomOpenApiPlusNegativeReturnCodeError, -) -from koapy.backtrader.KiwoomOpenApiPlusEventStreamer import ( - KiwoomOpenApiPlusEventStreamer, -) -from koapy.utils.logging.Logging import Logging - - -class KiwoomOpenApiPlusJsonError(KiwoomOpenApiPlusNegativeReturnCodeError): - def __init__(self, code, message=None): - if isinstance(code, KiwoomOpenApiPlusError): - err = code - code = getattr( - err, "code", KiwoomOpenApiPlusNegativeReturnCodeError.OP_ERR_FAIL - ) - message = err.message - super().__init__(code, message) - - def error_response(self, description=None): - response = { - "code": self.code, - "message": self.message, - "description": description or "", - } - return response - - -class KiwoomOpenApiPlusTimeFrameError(KiwoomOpenApiPlusJsonError): - def __init__(self): - super().__init__(code=597, message="Given TimeFrame is not supported") - - -class HistoricalPriceRecord( - collections.namedtuple( - "HistoricalPriceRecord", ["time", "open", "high", "low", "close", "volume"] - ) -): - - __slots__ = () - - _krx_timezone = get_calendar("XKRX").tz - - @classmethod - def from_tuple(cls, tup): - if "일자" in tup._fields: - dt = datetime.datetime.strptime(tup.일자, "%Y%m%d") - dt = cls._krx_timezone.localize(dt) - time = dt.timestamp() * (10**6) # pylint: disable=redefined-outer-name - elif "체결시간" in tup._fields: - dt = datetime.datetime.strptime(tup.체결시간, "%Y%m%d%H%M%S") - dt = cls._krx_timezone.localize(dt) - time = dt.timestamp() * (10**6) - else: - raise KiwoomOpenApiPlusError("Cannot specify time") - open = abs(float(tup.시가)) # pylint: disable=redefined-builtin - high = abs(float(tup.고가)) - low = abs(float(tup.저가)) - close = abs(float(tup.현재가)) - volume = abs(float(tup.거래량)) - return cls(time, open, high, low, close, volume) - - @classmethod - def records_from_dataframe(cls, df): - return [cls.from_tuple(tup) for tup in df[::-1].itertuples()] - - @classmethod - def dict_records_from_dataframe(cls, df): - return [msg._asdict() for msg in cls.records_from_dataframe(df)] - - -class API: - - # 우선은 최대한 기존 Oanda 구현을 유지한채로 맞춰서 동작할 수 있도록 구현해놓고 - # 추후 동작이 되는게 확인되면 천천히 하단 API 에 맞게 최적화를 하는 방향으로 작업하는 것으로... - - _krx_timezone = get_calendar("XKRX").tz - - def __init__(self, context): - self._context = context - self._codes = self._context.GetCodeListByMarketAsList() - - def __getattr__(self, name): - return getattr(self._context, name) - - def get_instruments_original( - self, account, instruments - ): # TODO: 계좌에 따라 시장이 다를 수 있음 - instruments = self.GetStockInfoAsDataFrame(instruments) - instruments = [tup._asdict() for tup in instruments.itertuples(index=False)] - response = {"instruments": instruments} - return response - - def get_instruments(self, account, instruments): - if isinstance(instruments, str): - instruments = [instruments] - instruments = [inst for inst in instruments if inst in self._codes] - response = {"instruments": instruments} - return response - - def get_history(self, trcode, inputs, dtbegin=None, dtend=None): - if trcode == "opt10079": - code = inputs["종목코드"] - interval = inputs["틱범위"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetTickStockDataAsDataFrame( - code, interval, dtend, dtbegin, adjusted_price=adjusted_price - ) - elif trcode == "opt10080": - code = inputs["종목코드"] - interval = inputs["틱범위"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetMinuteStockDataAsDataFrame( - code, interval, dtend, dtbegin, adjusted_price=adjusted_price - ) - elif trcode == "opt10081": - code = inputs["종목코드"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetDailyStockDataAsDataFrame( - code, dtend, dtbegin, adjusted_price=adjusted_price - ) - elif trcode == "opt10082": - code = inputs["종목코드"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetWeeklyStockDataAsDataFrame( - code, dtend, dtbegin, adjusted_price=adjusted_price - ) - elif trcode == "opt10083": - code = inputs["종목코드"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetMonthlyStockDataAsDataFrame( - code, dtend, dtbegin, adjusted_price=adjusted_price - ) - elif trcode == "opt10094": - code = inputs["종목코드"] - adjusted_price = inputs.get("수정주가구분") == "1" - df = self.GetYearlyStockDataAsDataFrame( - code, dtend, dtbegin, adjusted_price=adjusted_price - ) - else: - raise KiwoomOpenApiPlusError("Unexpected trcode %s" % trcode) - - candles = HistoricalPriceRecord.dict_records_from_dataframe(df) - response = {"candles": candles} - return response - - def get_positions(self, account): - _summary, foreach = self.GetAccountEvaluationStatusAsSeriesAndDataFrame(account) - positions = [ - { - "instrument": tup.종목코드, - "side": "buy", - "units": float(tup.보유수량), - "avgPrice": float(tup.매입금액) / float(tup.보유수량), - } - for tup in foreach.itertuples() - ] - response = {"positions": positions} - return response - - def get_account(self, account): - summary, _foreach = self.GetAccountEvaluationStatusAsSeriesAndDataFrame(account) - response = { - "marginAvail": float(summary["D+2추정예수금"]), - "balance": float(summary["추정예탁자산"]), - } - return response - - def create_order(self, account, **kwargs): - request_name = "create_order({}, {})".format(account, kwargs) - screen_no = "" - account_no = account - order_type = { - "buy": 1, - "sell": 2, - }[kwargs["side"]] - code = kwargs["instrument"] - quantity = kwargs["units"] - price = kwargs.get("price", 0) - quote_type = { - "limit": "00", - "market": "03", - }[kwargs["type"]] - original_order_no = "" - responses = self.OrderCall( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - ) - - MAX_ORDER_RES_CNT = 5 - for i in range(MAX_ORDER_RES_CNT): - res = next(responses) - if ( - res.name == "OnReceiveChejanData" - and res.arguments[0].string_value == "0" # 주문접수 or 체결 - ): - break - - accept_data = dict(zip(res.single_data.names, res.single_data.values)) - result = {"orderOpened": {"id": accept_data["주문번호"]}} - return result - - def close_order(self, account, oid, size, dataname): - request_name = "close_order({}, {}, {}, {})".format( - account, oid, size, dataname - ) - screen_no = "" - account_no = account - order_type = 3 if size >= 0 else 4 - code = dataname - quantity = 0 - price = 0 - quote_type = "" - original_order_no = oid - responses = self.OrderCall( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - ) - _msg = next(responses) - _tr = next(responses) - _accept = next(responses) - confirm = next(responses) - confirm_data = dict(zip(confirm.single_data.names, confirm.single_data.values)) - result = {"orderOpened": {"id": confirm_data["주문번호"]}} - return result - - def get_today_quotes_by_code(self, codes=None): - if codes is None: - codes = self._codes - df = self.GetStockQuoteInfoAsDataFrame(codes) - dt = pd.to_datetime( - df["일자"].str.cat(df["체결시간"]), format="%Y%m%d%H%M%S" - ).dt.tz_localize(self._krx_timezone) - dt = dt.astype(np.int64) // 10**3 - df = pd.DataFrame( - { - "dataname": df["종목코드"], - "time": dt, - "open": df["시가"].astype(float).abs(), - "high": df["고가"].astype(float).abs(), - "low": df["저가"].astype(float).abs(), - "close": df["종가"].astype(float).abs(), - "volume": df["거래량"].astype(float).abs(), - } - ) - msgs = {tup.dataname: tup._asdict() for tup in df.itertuples(index=False)} - return msgs - - -class MetaSingleton(MetaParams): - def __init__(cls, clsname, bases, dct): - super().__init__(clsname, bases, dct) - cls._singleton = None - - def __call__(cls, *args, **kwargs): - if cls._singleton is None: - cls._singleton = super().__call__(*args, **kwargs) - - return cls._singleton - - -class MetaKiwoomOpenApiPlusStore(type(Logging), MetaSingleton): - pass - - -class KiwoomOpenApiPlusStore(Logging, metaclass=MetaKiwoomOpenApiPlusStore): - # pylint: disable=protected-access - - BrokerCls = None # broker class will auto register - DataCls = None # data class will auto register - - params = ( - ("account", ""), - ("account_tmout", 60.0), # TODO: 60초마다 TR 을 날리는데 정말 이게 필요한가? - ) - - _DTEPOCH = datetime.datetime(1970, 1, 1) - - @classmethod - def getdata(cls, *args, **kwargs): - if cls.DataCls is None: - from koapy.backtrader.KiwoomOpenApiPlusData import KiwoomOpenApiPlusData - - cls.DataCls = KiwoomOpenApiPlusData - return cls.DataCls(*args, **kwargs) # pylint: disable=not-callable - - @classmethod - def getbroker(cls, *args, **kwargs): - if cls.BrokerCls is None: - from koapy.backtrader.KiwoomOpenApiPlusBroker import KiwoomOpenApiPlusBroker - - cls.BrokerCls = KiwoomOpenApiPlusBroker - return cls.BrokerCls(*args, **kwargs) # pylint: disable=not-callable - - def __init__(self, context=None): - super().__init__() - - self.notifs = collections.deque() - - self._env = None - self.broker = None - - self.datas = list() - self.datanames = list() - - self._ever_started = False - self._today_quotes_by_code = None - self._today_quotes_by_code_done = threading.Event() - - self._orders = collections.OrderedDict() # map order.ref to oid - self._ordersrev = collections.OrderedDict() # map oid to order.ref - self._transpend = collections.defaultdict(collections.deque) - - if context is None: - context = KiwoomOpenApiPlusEntrypoint() - - self._context = context - self._context.EnsureConnected() - - if not self.p.account: - self.p.account = self._context.GetFirstAvailableAccount() - - self.api = API(self._context) - - self._cash = 0.0 - self._value = 0.0 - self._evt_acct = threading.Event() - - self.q_account = None - self.q_ordercreate = None - self.q_orderclose = None - - self._tmoffset = datetime.timedelta() - - def start(self, data=None, broker=None): - if not self._ever_started: - self._ever_started = True - self._today_quotes_by_code = self.api.get_today_quotes_by_code( - self.datanames - ) - self._today_quotes_by_code_done.set() - - if data is None and broker is None: - return - - if data is not None: - self._env = data._env # pylint: disable=protected-access - self.datas.append(data) - - if self.broker is not None: - self.broker.data_started(data) - - self._today_quotes_by_code_done.wait() - - elif broker is not None: - self.broker = broker - self.streaming_events() - self.broker_threads() - - def initial_today_historical_msg(self, data=None): - if data is not None: - return self._today_quotes_by_code.get(data.p.dataname) - - def stop(self): - pass - - def put_notification(self, msg, *args, **kwargs): - self.notifs.append((msg, args, kwargs)) - - def get_notifications(self): - self.notifs.append(None) - return [x for x in iter(self.notifs.popleft, None)] - - def timeoffset(self): - return self._tmoffset - - _GRANULARITIES = { - (TimeFrame.Ticks, 1): ("opt10079", {"종목코드": "", "틱범위": "1", "수정주가구분": "1"}), - (TimeFrame.Ticks, 3): ("opt10079", {"종목코드": "", "틱범위": "3", "수정주가구분": "1"}), - (TimeFrame.Ticks, 5): ("opt10079", {"종목코드": "", "틱범위": "5", "수정주가구분": "1"}), - (TimeFrame.Ticks, 10): ("opt10079", {"종목코드": "", "틱범위": "10", "수정주가구분": "1"}), - (TimeFrame.Ticks, 30): ("opt10079", {"종목코드": "", "틱범위": "30", "수정주가구분": "1"}), - (TimeFrame.Minutes, 1): ("opt10080", {"종목코드": "", "틱범위": "1", "수정주가구분": "1"}), - (TimeFrame.Minutes, 3): ("opt10080", {"종목코드": "", "틱범위": "3", "수정주가구분": "1"}), - (TimeFrame.Minutes, 5): ("opt10080", {"종목코드": "", "틱범위": "5", "수정주가구분": "1"}), - (TimeFrame.Minutes, 10): ("opt10080", {"종목코드": "", "틱범위": "10", "수정주가구분": "1"}), - (TimeFrame.Minutes, 15): ("opt10080", {"종목코드": "", "틱범위": "15", "수정주가구분": "1"}), - (TimeFrame.Minutes, 30): ("opt10080", {"종목코드": "", "틱범위": "30", "수정주가구분": "1"}), - (TimeFrame.Minutes, 45): ("opt10080", {"종목코드": "", "틱범위": "45", "수정주가구분": "1"}), - (TimeFrame.Minutes, 60): ("opt10080", {"종목코드": "", "틱범위": "60", "수정주가구분": "1"}), - (TimeFrame.Days, 1): ("opt10081", {"종목코드": "", "기준일자": "", "수정주가구분": "1"}), - (TimeFrame.Weeks, 1): ( - "opt10082", - {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, - ), - (TimeFrame.Months, 1): ( - "opt10083", - {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, - ), - (TimeFrame.Years, 1): ( - "opt10094", - {"종목코드": "", "기준일자": "", "끝일자": "", "수정주가구분": "1"}, - ), - } - - def get_granularity(self, timeframe, compression, default=None): - return self._GRANULARITIES.get((timeframe, compression), default) - - def get_instrument(self, dataname): - try: - insts = self.api.get_instruments(self.p.account, instruments=dataname) - except KiwoomOpenApiPlusError: - return None - - i = insts.get("instruments", [{}]) - inst = i[0] if len(i) else None - return inst - - def streaming_events(self, tmout=None): - q = queue.Queue() - kwargs = {"q": q, "tmout": tmout} - - t = threading.Thread(target=self._t_streaming_listener, kwargs=kwargs) - t.daemon = True - t.start() - - t = threading.Thread(target=self._t_streaming_events, kwargs=kwargs) - t.daemon = True - t.start() - return q - - def _t_streaming_listener(self, q, tmout=None): - while True: - trans = q.get() - self._transaction(trans) - - def _t_streaming_events(self, q, tmout=None): - if tmout is not None: - time.sleep(tmout) - streamer = KiwoomOpenApiPlusEventStreamer(self.api, q) - streamer.events() - - def candles(self, dataname, dtbegin, dtend, timeframe, compression): - kwargs = locals().copy() - kwargs.pop("self") - kwargs["q"] = q = queue.Queue() - t = threading.Thread(target=self._t_candles, kwargs=kwargs) - t.daemon = True - t.start() - return q - - def _t_candles(self, dataname, dtbegin, dtend, timeframe, compression, q): - trcode, inputs = self.get_granularity(timeframe, compression, (None, None)) - - if trcode is None: - e = KiwoomOpenApiPlusTimeFrameError() - q.put(e.error_response) - return - - inputs = inputs.copy() - inputs["종목코드"] = dataname - - if dtbegin is not None: - if "끝일자" in inputs: - inputs["끝일자"] = dtbegin.strftime("%Y%m%d") - - if dtend is not None: - if "기준일자" in inputs: - inputs["기준일자"] = dtend.strftime("%Y%m%d") - - try: - response = self.api.get_history(trcode, inputs, dtbegin, dtend) - except KiwoomOpenApiPlusError as e: - q.put(KiwoomOpenApiPlusJsonError(e).error_response()) - q.put(None) - return - - for candle in response.get("candles", []): - q.put(candle) - - q.put({}) - - def streaming_prices(self, dataname, tmout=None): - q = queue.Queue() - kwargs = {"q": q, "dataname": dataname, "tmout": tmout} - t = threading.Thread(target=self._t_streaming_prices, kwargs=kwargs) - t.daemon = True - t.start() - return q - - def _t_streaming_prices(self, dataname, q, tmout): - if tmout is not None: - time.sleep(tmout) - streamer = KiwoomOpenApiPlusEventStreamer(self.api, q) - streamer.rates(dataname) - - def get_cash(self): - return self._cash - - def get_value(self): - return self._value - - def get_positions(self): - try: - positions = self.api.get_positions(self.p.account) - except KiwoomOpenApiPlusError: - return None - - poslist = positions.get("positions", []) - return poslist - - def broker_threads(self): - self.q_account = queue.Queue() - self.q_account.put(True) # force an immediate update - t = threading.Thread(target=self._t_account) - t.daemon = True - t.start() - - self.q_ordercreate = queue.Queue() - t = threading.Thread(target=self._t_order_create) - t.daemon = True - t.start() - - self.q_orderclose = queue.Queue() - t = threading.Thread(target=self._t_order_cancel) - t.daemon = True - t.start() - - # Wait once for the values to be set - self._evt_acct.wait(self.p.account_tmout) - - def _t_account(self): - while True: - try: - msg = self.q_account.get(timeout=self.p.account_tmout) - if msg is None: - break # end of thread - except queue.Empty: # tmout -> time to refresh - pass - - try: - accinfo = self.api.get_account(self.p.account) - except Exception as e: # pylint: disable=broad-except - self.put_notification(e) - continue - - try: - self._cash = accinfo["marginAvail"] - self._value = accinfo["balance"] - except KeyError: - pass - - self._evt_acct.set() - - # from below, it's related to processing orders - - _ORDEREXECS = { - bt.Order.Market: "market", - bt.Order.Limit: "limit", - bt.Order.Stop: "stop", - bt.Order.StopLimit: "stop", - } - - def order_create(self, order, stopside=None, takeside=None, **kwargs): - okwargs = dict() - okwargs["instrument"] = order.data._dataname - okwargs["units"] = abs(order.created.size) - okwargs["side"] = "buy" if order.isbuy() else "sell" - okwargs["type"] = self._ORDEREXECS[order.exectype] - if order.exectype != bt.Order.Market: - okwargs["price"] = order.created.price - if order.valid is None: - # 1 year and datetime.max fail ... 1 month works - valid = datetime.datetime.utcnow() + datetime.timedelta(days=30) - else: - valid = order.data.num2date(order.valid) - # To timestamp with seconds precision - okwargs["expiry"] = int((valid - self._DTEPOCH).total_seconds()) - - if order.exectype == bt.Order.StopLimit: - okwargs["lowerBound"] = order.created.pricelimit - okwargs["upperBound"] = order.created.pricelimit - - if order.exectype == bt.Order.StopTrail: - okwargs["trailingStop"] = order.trailamount - - if stopside is not None: - okwargs["stopLoss"] = stopside.price - - if takeside is not None: - okwargs["takeProfit"] = takeside.price - - okwargs.update(**kwargs) # anything from the user - - self.q_ordercreate.put( - ( - order.ref, - okwargs, - ) - ) - return order - - _OIDSINGLE = ["orderOpened", "tradeOpened", "tradeReduced"] - _OIDMULTIPLE = ["tradesClosed"] - - def _t_order_create(self): - while True: - msg = self.q_ordercreate.get() - if msg is None: - break - - oref, okwargs = msg - try: - o = self.api.create_order(self.p.account, **okwargs) - except Exception as e: - self.logger.exception( - "Exception while create_order(%s, %s)", self.p.account, okwargs - ) - self.put_notification(e) - self.broker._reject(oref) - - # Ids are delivered in different fields and all must be fetched to - # match them (as executions) to the order generated here - oids = list() - for oidfield in self._OIDSINGLE: - if oidfield in o and "id" in o[oidfield]: - oids.append(o[oidfield]["id"]) - - for oidfield in self._OIDMULTIPLE: - if oidfield in o: - for suboidfield in o[oidfield]: - oids.append(suboidfield["id"]) - - if not oids: - self.logger.warning("Rejecting %s because no oids specified", oref) - self.broker._reject(oref) - return - - self._orders[oref] = oids[0] - self.broker._submit(oref) - if okwargs["type"] == "market": - self.broker._accept(oref) # taken immediately - - for oid in oids: - self._ordersrev[oid] = oref # maps ids to backtrader order - - # An transaction may have happened and was stored - tpending = self._transpend[oid] - tpending.append(None) # eom marker - while True: - trans = tpending.popleft() - if trans is None: - break - self._process_transaction(oid, trans) - - def order_cancel(self, order): - self.q_orderclose.put((order.ref, order.created.size, order.data.p.dataname)) - return order - - def _t_order_cancel(self): - while True: - msg = self.q_orderclose.get() - if msg is None: - break - - oref, size, dataname = msg - oid = self._orders.get(oref, None) - if oid is None: - continue # the order is no longer there - try: - o = self.api.close_order(self.p.account, oid, size, dataname) - except Exception as e: - self.logger.exception("Failed to close order") - continue # not cancelled - FIXME: notify - - self.broker._cancel(oref) - - _X_ORDER_CREATE = ( - "STOP_ORDER_CREATE", - "LIMIT_ORDER_CREATE", - "MARKET_IF_TOUCHED_ORDER_CREATE", - ) - - def _transaction(self, trans): - # Invoked from Streaming Events. May actually receive an event for an - # oid which has not yet been returned after creating an order. Hence - # store if not yet seen, else forward to processer - ttype = trans["type"] - if ttype == "MARKET_ORDER_CREATE": - try: - oid = trans["tradeReduced"]["id"] - except KeyError: - try: - oid = trans["tradeOpened"]["id"] - except KeyError: - return # cannot do anything else - - elif ttype in self._X_ORDER_CREATE: - oid = trans["id"] - elif ttype == "ORDER_FILLED": - oid = trans["orderId"] - - elif ttype == "ORDER_CANCEL": - oid = trans["orderId"] - - elif ttype == "TRADE_CLOSE": - oid = trans["id"] - pid = trans["tradeId"] - if pid in self._orders and False: # Know nothing about trade - return # can do nothing - - # Skip above - at the moment do nothing - # Received directly from an event in the WebGUI for example which - # closes an existing position related to order with id -> pid - # COULD BE DONE: Generate a fake counter order to gracefully - # close the existing position - msg = ( - "Received TRADE_CLOSE for unknown order, possibly generated" - " over a different client or GUI" - ) - self.put_notification(msg, trans) - return - - else: # Go aways gracefully - try: - oid = trans["id"] - except KeyError: - oid = "None" - - msg = "Received {} with oid {}. Unknown situation" - msg = msg.format(ttype, oid) - self.put_notification(msg, trans) - return - - try: - self._process_transaction(oid, trans) - except KeyError: # not yet seen, keep as pending - self._transpend[oid].append(trans) - - _X_ORDER_FILLED = ( - "MARKET_ORDER_CREATE", - "ORDER_FILLED", - "TAKE_PROFIT_FILLED", - "STOP_LOSS_FILLED", - "TRAILING_STOP_FILLED", - ) - - def _process_transaction(self, oid, trans): - try: - oref = self._ordersrev[oid] - except KeyError: - return - - ttype = trans["type"] - - if ttype in self._X_ORDER_FILLED: - size = trans["units"] - if trans["side"] == "sell": - size = -size - price = trans["price"] - self.broker._fill(oref, size, price, ttype=ttype) - - elif ttype in self._X_ORDER_CREATE: - self.broker._accept(oref) - self._ordersrev[oid] = oref - - elif ttype in "ORDER_CANCEL": - reason = trans["reason"] - if reason == "ORDER_FILLED": - pass # individual execs have done the job - elif reason == "TIME_IN_FORCE_EXPIRED": - self.broker._expire(oref) - elif reason == "CLIENT_REQUEST": - self.broker._cancel(oref) - else: # default action ... if nothing else - self.logger.warning("Rejecting %s since it's canceled", oref) - self.broker._reject(oref) diff --git a/koapy/backtrader/KrxHistoricalDailyPriceData.py b/koapy/backtrader/KrxHistoricalDailyPriceData.py deleted file mode 100644 index b64b8634..00000000 --- a/koapy/backtrader/KrxHistoricalDailyPriceData.py +++ /dev/null @@ -1,121 +0,0 @@ -import pandas as pd - -from backtrader import TimeFrame, date2num -from backtrader.feed import DataBase -from tqdm import tqdm - -from koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader import ( - KrxHistoricalDailyPriceDataForBacktestLoader, -) - - -class KrxHistoricalDailyPriceData(DataBase): - - # pylint: disable=no-member - - params = ( - ("loader", None), - ("symbol", None), - ("name", None), - ("fromdate", None), - ("todate", None), - ("compression", 1), - ("timeframe", TimeFrame.Days), - ("calendar", None), - ("lazy", False), - ) - - lines = ( - "amount", - "marketcap", - "shares", - ) - - def __init__(self): - super().__init__() - - assert self.p.loader - assert self.p.symbol - - assert self.p.timeframe == TimeFrame.Days - assert self.p.compression == 1 - - self.p.name = self.p.name or self.p.symbol or "" - - self._cursor = None - self._started_already = False - - if not self.p.lazy: - self.start() - - def _close_cursor(self): - if self._cursor is not None: - self._cursor.close() - self._cursor = None - - def _initialize_cursor(self): - self._close_cursor() - self._cursor = self.p.loader.load_as_cursor( - self.p.symbol, start_time=self.p.fromdate, end_time=self.p.todate - ) - - def start(self): - if not self._started_already: - self._initialize_cursor() - self._started_already = True - - def stop(self): - self._close_cursor() - self._started_already = False - - def _load(self): - if self._cursor is None: - return False - - try: - date, open_, high, low, close, volume, amount, marcap, shares = next( - self._cursor - ) - except StopIteration: - return False - else: - dt = pd.Timestamp(date) - - self.lines.datetime[0] = date2num(dt) - self.lines.open[0] = open_ - self.lines.high[0] = high - self.lines.low[0] = low - self.lines.close[0] = close - self.lines.volume[0] = volume - self.lines.openinterest[0] = 0.0 - - self.lines.amount[0] = amount - self.lines.marketcap[0] = marcap - self.lines.shares[0] = shares - - return True - - @classmethod - def adddata_fromfile( - cls, - cerebro, - filename, - symbols=None, - fromdate=None, - todate=None, - progress_bar=True, - ): - loader = KrxHistoricalDailyPriceDataForBacktestLoader(filename) - if symbols is None: - symbols = loader.get_symbols() - progress = tqdm(symbols, disable=not progress_bar) - for symbol in progress: - progress.set_description("Adding Symbol [%s]" % symbol) - data = cls( - loader=loader, - symbol=symbol, - fromdate=fromdate, - todate=todate, - name=symbol, - ) # pylint: disable=unexpected-keyword-arg - cerebro.adddata(data, name=data.p.name) diff --git a/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.py b/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.py deleted file mode 100644 index 4fb3d07b..00000000 --- a/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite.py +++ /dev/null @@ -1,119 +0,0 @@ -import pandas as pd - -from backtrader import TimeFrame, date2num -from sqlalchemy import create_engine, inspect -from tqdm import tqdm - -from koapy.backtrader.SQLiteData import SQLiteData -from koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader import ( - KrxHistoricalDailyPriceDataForBacktestLoader, -) - - -class KrxHistoricalDailyPriceDataFromSQLite(SQLiteData): - - # pylint: disable=no-member - - params = ( - ("engine", None), - ("symbol", None), - ("name", None), - ("fromdate", None), - ("todate", None), - ("compression", 1), - ("timeframe", TimeFrame.Days), - ("calendar", None), - ("timestampcolumn", 0), - ("timestampcolumntimezone", None), - ("lazy", False), - ) - - lines = ( - "amount", - "marketcap", - "shares", - ) - - def __init__(self): - assert self.p.timeframe == TimeFrame.Days - assert self.p.compression == 1 - - self.p.tablename = self.p.tablename or self.p.symbol or None - self.p.name = self.p.name or self.p.symbol or self.p.tablename or "" - - super().__init__() - - def _load(self): - if self._cursor is None: - return False - - try: - date, open_, high, low, close, volume, amount, marcap, shares = next( - self._cursor - ) - except StopIteration: - return False - else: - dt = pd.Timestamp(date) - - self.lines.datetime[0] = date2num(dt) - self.lines.open[0] = open_ - self.lines.high[0] = high - self.lines.low[0] = low - self.lines.close[0] = close - self.lines.volume[0] = volume - self.lines.openinterest[0] = 0.0 - - self.lines.amount[0] = amount - self.lines.marketcap[0] = marcap - self.lines.shares[0] = shares - - return True - - @classmethod - def dump_from_store( - cls, - source_filename, - dest_filename, - symbols=None, - fromdate=None, - todate=None, - progress_bar=True, - ): - loader = KrxHistoricalDailyPriceDataForBacktestLoader(source_filename) - if symbols is None: - symbols = loader.get_symbols() - engine = create_engine("sqlite:///" + dest_filename) - progress = tqdm(symbols, disable=not progress_bar) - for symbol in progress: - progress.set_description("Dumping Symbol [%s]" % symbol) - data = loader.load(symbol, start_time=fromdate, end_time=todate) - data.to_sql(symbol, engine, if_exists="replace") - - @classmethod - def adddata_fromfile( - cls, - cerebro, - filename, - symbols=None, - fromdate=None, - todate=None, - progress_bar=True, - ): - engine = create_engine("sqlite:///" + filename) - inspector = inspect(engine) - if symbols is None: - symbols = inspector.get_table_names() - progress = tqdm(symbols, disable=not progress_bar) - for symbol in progress: - progress.set_description("Adding Symbol [%s]" % symbol) - # pylint: disable=unexpected-keyword-arg - data = cls( - engine=engine, - tablename=symbol, - fromdate=fromdate, - todate=todate, - symbol=symbol, - name=symbol, - ) - cerebro.adddata(data, name=data.p.name) diff --git a/koapy/backtrader/KrxTradingCalendar.py b/koapy/backtrader/KrxTradingCalendar.py deleted file mode 100644 index 2c500baf..00000000 --- a/koapy/backtrader/KrxTradingCalendar.py +++ /dev/null @@ -1,57 +0,0 @@ -import datetime - -import pytz - -from backtrader.tradingcal import TradingCalendarBase -from backtrader.utils.py3 import string_types -from pandas import DataFrame, DatetimeIndex, Timestamp - - -class ExchangeCalendarsTradingCalendar(TradingCalendarBase): - - # pylint: disable=no-member - - params = ( - ("calendar", None), - ("cachesize", 365), - ) - - def __init__(self): - super().__init__() - - self._calendar = self.p.calendar - - if isinstance(self._calendar, string_types): - from exchange_calendars import get_calendar - - self._calendar = get_calendar(self._calendar) - - self.dcache = DatetimeIndex([0.0]) - self.idcache = DataFrame(index=DatetimeIndex([0.0])) - self.csize = datetime.timedelta(days=self.p.cachesize) - - def _nextday(self, day): - d = day + self._calendar.day - return d, d.isocalendar() - - def schedule( - self, day, tz=None - ): # pylint: disable=arguments-differ,unused-argument - """ - day: expecting naive datetime.datetime day in utc timezone - tz: treat/localize internal naive datetimes to this timezone - returns: (opening, closing) naive datetime.datetime pair in utc timezone - """ - session = Timestamp(day, tz=pytz.UTC).normalize() - opening, closing = self._calendar.open_and_close_for_session(session) - opening = opening.tz.localize(None).to_pydatetime() - closing = closing.tz.localize(None).to_pydatetime() - return opening, closing - - -class KrxTradingCalendar(ExchangeCalendarsTradingCalendar): - - params = ( - ("calendar", "XKRX"), - ("cachesize", 365), - ) diff --git a/koapy/backtrader/SQLAlchemyData.py b/koapy/backtrader/SQLAlchemyData.py deleted file mode 100644 index 5ad19a9c..00000000 --- a/koapy/backtrader/SQLAlchemyData.py +++ /dev/null @@ -1,127 +0,0 @@ -import datetime - -import pandas as pd - -from backtrader import date2num -from backtrader.feed import DataBase -from sqlalchemy import MetaData, Table, create_engine, select - - -class SQLAlchemyData(DataBase): - - # pylint: disable=no-member - - params = ( - ("url", None), - ("engine", None), - ("connection", None), - ("tablename", None), - ("timestampcolumn", 0), - ("timestampcolumntimezone", None), - ("timestampcolumnsort", False), - ("lazy", True), - ) - - def __init__(self): - super().__init__() - - assert self.p.url - assert self.p.tablename - - self._engine = self.p.engine - self._should_dispose = False - - self._cursor = None - - if self.p.timestampcolumntimezone is None: - self.p.timestampcolumntimezone = datetime.datetime.now().astimezone().tzinfo - - self._started_already = False - - if not self.p.lazy: - self.start() - - def _dispose_engine(self): - if self._engine is not None and self._should_dispose: - self._engine.dispose() - self._engine = None - - def _initialize_engine(self): - self._dispose_engine() - - self._engine = self.p.engine - self._should_dispose = False - - if self._engine is None: - if self.p.connection is not None: - self._engine = create_engine( - self.p.url, creator=lambda: self.p.connection - ) - self._should_dispose = False - else: - self._engine = create_engine(self.p.url) - self._should_dispose = True - - assert self._engine is not None - - def _close_cursor(self): - if self._cursor is not None: - self._cursor.close() - self._cursor = None - - def _initialize_cursor(self): - self._close_cursor() - - metadata = MetaData() - table = Table(self.p.tablename, metadata, autoload_with=self._engine) - timestampcolumn = table.columns[ - self.p.timestampcolumn - ] # pylint: disable=unsubscriptable-object - statement = select(table) - - if self.p.timestampcolumnsort: - statement = statement.order_by(timestampcolumn) - - if self.p.fromdate is not None: - fromdate = pd.Timestamp(self.p.fromdate, tz=self.p.timestampcolumntimezone) - statement = statement.where(timestampcolumn >= fromdate) - - if self.p.todate is not None: - todate = pd.Timestamp(self.p.todate, tz=self.p.timestampcolumntimezone) - statement = statement.where(timestampcolumn <= todate) - - statement = statement.execution_options(stream_results=True) - - self._cursor = self._engine.execute(statement) - - def start(self): - if not self._started_already: - self._initialize_engine() - self._initialize_cursor() - self._started_already = True - - def stop(self): - self._close_cursor() - self._dispose_engine() - self._started_already = False - - def _load(self): - if self._cursor is None: - return False - - try: - date, open_, high, low, close, volume, openinterest = next(self._cursor) - except StopIteration: - return False - else: - dt = pd.Timestamp(date) - - self.lines.datetime[0] = date2num(dt) - self.lines.open[0] = open_ - self.lines.high[0] = high - self.lines.low[0] = low - self.lines.close[0] = close - self.lines.volume[0] = volume - self.lines.openinterest[0] = openinterest - - return True diff --git a/koapy/backtrader/SQLAlchemySQLiteData.py b/koapy/backtrader/SQLAlchemySQLiteData.py deleted file mode 100644 index 78fb66c2..00000000 --- a/koapy/backtrader/SQLAlchemySQLiteData.py +++ /dev/null @@ -1,17 +0,0 @@ -from .SQLAlchemyData import SQLAlchemyData - - -class SQLAlchemySQLiteData(SQLAlchemyData): - - # pylint: disable=no-member - - params = (("filename", None),) - - def __init__(self): - if not self.p.url: - self.p.url = "sqlite://" - - if self.p.filename: - self.p.url += "/" + self.p.filename - - super().__init__() diff --git a/koapy/backtrader/SQLiteData.py b/koapy/backtrader/SQLiteData.py deleted file mode 100644 index 6348ae69..00000000 --- a/koapy/backtrader/SQLiteData.py +++ /dev/null @@ -1,141 +0,0 @@ -import datetime -import sqlite3 - -import pandas as pd - -from backtrader import date2num -from backtrader.feed import DataBase - - -class SQLiteData(DataBase): - - # pylint: disable=no-member - - params = ( - ("filename", None), - ("connection", None), - ("engine", None), - ("tablename", None), - ("timestampcolumn", 0), - ("timestampcolumntimezone", None), - ("timestampcolumnsort", False), - ("timestampcolumnformat", None), # '%Y-%m-%d %H:%M:%S.%f' - ("lazy", True), - ) - - def __init__(self): - super().__init__() - - assert self.p.tablename - - self._connection = self.p.connection - self._should_close = False - - self._cursor = None - - if self.p.timestampcolumntimezone is None: - self.p.timestampcolumntimezone = datetime.datetime.now().astimezone().tzinfo - - self._started_already = False - - if not self.p.lazy: - self.start() - - def _close_connection(self): - if self._connection is not None and self._should_close: - self._connection.close() - self._connection = None - - def _initialize_connection(self): - self._close_connection() - - self._connection = self.p.connection - self._should_close = False - - if self._connection is None: - if self.p.engine is not None: - self._connection = self.p.engine.raw_connection() - self._should_close = True - elif self.p.filename: - self._connection = sqlite3.connect( - self.p.filename, check_same_thread=False - ) - self._should_close = True - - assert self._connection is not None - - def _close_cursor(self): - if self._cursor is not None: - self._cursor.close() - self._cursor = None - - def _initialize_cursor(self): - self._close_cursor() - - self._cursor = self._connection.cursor() - - timestampcolumn = self.p.timestampcolumn - - if isinstance(timestampcolumn, int): - self._cursor.execute("SELECT * FROM '{}' LIMIT 0".format(self.p.tablename)) - timestampcolumn = self._cursor.description[timestampcolumn][0] - - statement = "SELECT * FROM '{}'".format(self.p.tablename) - - condition_prefix = " WHERE " - parameters = [] - - if self.p.fromdate is not None: - fromdate = pd.Timestamp(self.p.fromdate, tz=self.p.timestampcolumntimezone) - if self.p.timestampcolumnformat: - fromdate = fromdate.strftime(self.p.timestampcolumnformat) - statement += condition_prefix - statement += "'{}' >= ?".format(timestampcolumn) - parameters.append(fromdate) - condition_prefix = " AND " - - if self.p.todate is not None: - todate = pd.Timestamp(self.p.todate, tz=self.p.timestampcolumntimezone) - if self.p.timestampcolumnformat: - todate = fromdate.strftime(self.p.timestampcolumnformat) - statement += condition_prefix - statement += "'{}' <= ?".format(timestampcolumn) - parameters.append(todate) - condition_prefix = " AND " - - if self.p.timestampcolumnsort: - statement += " ORDER BY '{}' ASC".format(timestampcolumn) - - self._cursor.execute(statement, parameters) - - def start(self): - if not self._started_already: - self._initialize_connection() - self._initialize_cursor() - self._started_already = True - - def stop(self): - self._close_cursor() - self._close_connection() - self._started_already = False - - def _load(self): - if self._cursor is None: - return False - - try: - date, open_, high, low, close, volume, openinterest = next(self._cursor) - except StopIteration: - return False - else: - dt = pd.Timestamp(date) - - self.lines.datetime[0] = date2num(dt) - self.lines.open[0] = open_ - self.lines.high[0] = high - self.lines.low[0] = low - self.lines.close[0] = close - self.lines.volume[0] = volume - self.lines.openinterest[0] = openinterest - - return True diff --git a/koapy/backtrader/__init__.py b/koapy/backtrader/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backtrader/examples/__init__.py b/koapy/backtrader/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/backtrader/examples/kiwoom_broker_integration.py b/koapy/backtrader/examples/kiwoom_broker_integration.py deleted file mode 100644 index b365e21c..00000000 --- a/koapy/backtrader/examples/kiwoom_broker_integration.py +++ /dev/null @@ -1,181 +0,0 @@ -import logging - -logging.basicConfig( - format="%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - level=logging.DEBUG, -) - -import datetime - -import backtrader as bt - -from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore - - -class TestStrategy(bt.Strategy): - - params = [ - ("exitbars", 5), - ("printlog", True), - ] - - def __init__(self): - super().__init__() - - self.dataclose = self.datas[0].close - - self.order = None - self.order_cancel = None - self.buyprice = None - self.buycomm = None - - self.bar_executed = 0 - - def log(self, fmt, *args, doprint=False, **kwargs): - if self.params.printlog or doprint: # pylint: disable=no-member - try: - dt = self.datas[0].datetime.datetime(0, naive=False) - except IndexError: - dt = datetime.datetime.now() - fmt = "{}, {}".format(dt, fmt) - logging.info(fmt, *args, **kwargs) - - def notify_order(self, order): - if order.status in [order.Submitted, order.Accepted]: - return - - if order.status in [order.Completed]: - if order.isbuy(): - self.log( - "Buy Exuecuted, Size: %d, Price: %.2f, Cost: %.2f, Comm: %.2f", - order.executed.size, - order.executed.price, - order.executed.value, - order.executed.comm, - ) - self.buyprice = order.executed.price - self.buycomm = order.executed.comm - elif order.issell(): - self.log( - "Sell Executed, Size: %d, Price: %.2f, Cost: %.2f, Comm: %.2f", - order.executed.size, - order.executed.price, - order.executed.value, - order.executed.comm, - ) - - self.order = None - self.bar_executed = len(self) - - elif order.status in [order.Canceled]: - self.log("Order Canceled") - if self.order == self.order_cancel: - self.order = None - self.order_cancel = None - elif order.status in [order.Margin]: - self.log("Order Margin") - if self.order == self.order_cancel: - self.order = None - self.order_cancel = None - elif order.status in [order.Rejected]: - self.log("Order Rejected") - if self.order == self.order_cancel: - self.order = None - self.order_cancel = None - - def notify_trade(self, trade): - if not trade.isclosed: - return - - self.log("Operation Profit, Gross: %.2f, Net: %.2f", trade.pnl, trade.pnlcomm) - - def next_market(self): - self.log("Close, %.2f", self.dataclose[0]) - - if self.order: - return - - if not self.position: - self.log("Buy Create, %.2f", self.dataclose[0]) - self.order = self.buy() - else: - if len(self) >= ( - self.bar_executed + self.params.exitbars - ): # pylint: disable=no-member - self.log("Sell Create, %.2f", self.dataclose[0]) - self.order = self.sell() - - def next_limit(self): - self.log("Close, %.2f", self.dataclose[0]) - - if self.order: - if len(self) >= ( - self.bar_executed + self.params.exitbars - ): # pylint: disable=no-member - if not self.order_cancel: - self.log("Cancel Create") - self.cancel(self.order) - self.order_cancel = self.order - else: - if not self.position: - self.log("Buy Create, %.2f", self.dataclose[0]) - self.order = self.buy( - exectype=bt.Order.Limit, price=self.dataclose[0] - 1000.0 - ) - self.bar_executed = len(self) - else: - if len(self) >= ( - self.bar_executed + self.params.exitbars - ): # pylint: disable=no-member - self.log("No Sell Create, %.2f", self.dataclose[0]) - - def start(self): - self.log("Starting Portfolio Value: %.2f", self.broker.getvalue(), doprint=True) - - def next(self): - return self.next_limit() - - def stop(self): - self.log("Final Portfolio Value: %.2f", self.broker.getvalue(), doprint=True) - - -def main(): - cerebro = bt.Cerebro() - - kiwoomstore = KiwoomOpenApiPlusStore() - cerebro.broker = kiwoomstore.getbroker() - - data = kiwoomstore.getdata( - dataname="005930", - backfill_start=False, - timeframe=bt.TimeFrame.Ticks, - compression=1, - ) - cerebro.resampledata( - data, name="005930", timeframe=bt.TimeFrame.Seconds, compression=1 - ) - cerebro.replaydata( - data, name="005930-1day", timeframe=bt.TimeFrame.Days, compression=1 - ) - - data = kiwoomstore.getdata( - dataname="035420", - backfill_start=False, - timeframe=bt.TimeFrame.Ticks, - compression=1, - ) - cerebro.resampledata( - data, name="035420", timeframe=bt.TimeFrame.Seconds, compression=1 - ) - cerebro.replaydata( - data, name="035420-1day", timeframe=bt.TimeFrame.Days, compression=1 - ) - - cerebro.addtz("Asia/Seoul") - cerebro.addstrategy(TestStrategy) - - cerebro.run() - - -if __name__ == "__main__": - main() diff --git a/koapy/backtrader/examples/kiwoom_data_integration.py b/koapy/backtrader/examples/kiwoom_data_integration.py deleted file mode 100644 index 4178c91f..00000000 --- a/koapy/backtrader/examples/kiwoom_data_integration.py +++ /dev/null @@ -1,50 +0,0 @@ -import logging - -logging.basicConfig( - format="%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - level=logging.DEBUG, -) - -import backtrader as bt - -from koapy.backtrader.examples.vanila_quickstart import OrclStrategy -from koapy.backtrader.KiwoomOpenApiPlusBroker import KiwoomOpenApiPlusCommInfo -from koapy.backtrader.KiwoomOpenApiPlusStore import KiwoomOpenApiPlusStore - - -def main(): - logging.info("Creating Cerebro") - cerebro = bt.Cerebro() # pylint: disable=unexpected-keyword-arg - - logging.info("Initializing Kiwoom Store") - kiwoomstore = KiwoomOpenApiPlusStore() - - logging.info("Getting data") - historial_data = kiwoomstore.getdata(dataname="005930", historical=True) - realtime_data = kiwoomstore.getdata( - dataname="005930", - backfill_start=False, - timeframe=bt.TimeFrame.Ticks, - compression=1, - ) - - logging.info("Adding data") - cerebro.adddata(historial_data) - - logging.info("Configuring others") - cerebro.addsizer(bt.sizers.FixedSize, stake=10) - cerebro.addtz("Asia/Seoul") - - cerebro.broker.setcash(30000000.0) - cerebro.broker.addcommissioninfo(KiwoomOpenApiPlusCommInfo()) - - logging.info("Setting strategy") - cerebro.addstrategy(OrclStrategy, printlog=True) - - logging.info("Starting Portfolio Value: %.2f", cerebro.broker.getvalue()) - cerebro.run() - logging.info("Final Portfolio Value: %.2f", cerebro.broker.getvalue()) - - -if __name__ == "__main__": - main() diff --git a/koapy/backtrader/examples/vanila_quickstart.py b/koapy/backtrader/examples/vanila_quickstart.py deleted file mode 100644 index 8810c3ff..00000000 --- a/koapy/backtrader/examples/vanila_quickstart.py +++ /dev/null @@ -1,162 +0,0 @@ -import datetime -import logging -import os -import sys - -import backtrader as bt - -logging.basicConfig( - format="%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - level=logging.DEBUG, -) - - -class OrclStrategy(bt.Strategy): - - params = [ - ("exitbars", 5), - ("maperiod", 15), - ("printlog", False), - ] - - def __init__(self): - super().__init__() - - self.dataclose = self.datas[0].close - - self.order = None - self.buyprice = None - self.buycomm = None - - self.bar_executed = 0 - - self.sma = bt.indicators.SimpleMovingAverage( - self.datas[0], period=self.params.maperiod - ) # pylint: disable=no-member - - def log(self, fmt, *args, doprint=False, **kwargs): - if self.params.printlog or doprint: # pylint: disable=no-member - dt = self.datas[0].datetime.datetime(0, naive=False) - fmt = "{}, {}".format(dt, fmt) - logging.info(fmt, *args, **kwargs) - - def notify_order(self, order): - if order.status in [order.Submitted, order.Accepted]: - return - - if order.status in [order.Completed]: - if order.isbuy(): - self.log( - "Buy Exuecuted, Size: %d, Price: %.2f, Cost: %.2f, Comm: %.2f", - order.executed.size, - order.executed.price, - order.executed.value, - order.executed.comm, - ) - self.buyprice = order.executed.price - self.buycomm = order.executed.comm - elif order.issell(): - self.log( - "Sell Executed, Size: %d, Price: %.2f, Cost: %.2f, Comm: %.2f", - order.executed.size, - order.executed.price, - order.executed.value, - order.executed.comm, - ) - - self.bar_executed = len(self) - - elif order.status in [order.Canceled, order.Margin, order.Rejected]: - self.log("Order Canceled/Margin/Rejected") - - self.order = None - - def notify_trade(self, trade): - if not trade.isclosed: - return - - self.log("Operation Profit, Gross: %.2f, Net: %.2f", trade.pnl, trade.pnlcomm) - - def next_simple(self): - self.log("Close, %.2f", self.dataclose[0]) - - if self.order: - return - - if not self.position: - if self.dataclose[0] < self.dataclose[-1]: - if self.dataclose[-1] < self.dataclose[-2]: - self.log("Buy Create, %.2f", self.dataclose[0]) - self.order = self.buy() - - else: - if len(self) >= ( - self.bar_executed + self.params.exitbars - ): # pylint: disable=no-member - self.log("Sell Create, %.2f", self.dataclose[0]) - self.order = self.sell() - - def next_with_indicator(self): - self.log("Close, %.2f", self.dataclose[0]) - - if self.order: - return - - if not self.position: - if self.dataclose[0] > self.sma[0]: - self.log("Buy Create, %.2f", self.dataclose[0]) - self.order = self.buy() - - else: - if self.dataclose[0] < self.sma[0]: - self.log("Sell Create, %.2f", self.dataclose[0]) - self.order = self.sell() - - def next(self): - return self.next_with_indicator() - - def stop(self): - self.log( - "(MA Period: %2d) Ending Value: %.2f", - self.params.maperiod, - self.broker.getvalue(), - doprint=True, - ) # pylint: disable=no-member - - -def main(): - cerebro = bt.Cerebro() - - _strats = cerebro.optstrategy(OrclStrategy, maperiod=range(10, 31)) - - modpath = os.path.dirname(os.path.abspath(sys.argv[0])) - - # goto https://finance.yahoo.com/quote/ORCL/history and download historical data as csv - datapath = os.path.join(modpath, "data/orcl-1986-2020.csv") - - data = bt.feeds.YahooFinanceCSVData( - dataname=datapath, - # Do not pass values before this date - fromdate=datetime.datetime(2000, 1, 1), - # Do not pass values after this date - todate=datetime.datetime(2000, 12, 31), - reverse=False, - ) - - cerebro.adddata(data) - - cerebro.broker.setcash(100000.0) - - cerebro.addsizer(bt.sizers.FixedSize, stake=10) - - cerebro.broker.setcommission(commission=0.001) - - logging.info("Starting Portfolio Value: %.2f", cerebro.broker.getvalue()) - - cerebro.run(maxcpus=1) - - logging.info("Final Portfolio Value: %.2f", cerebro.broker.getvalue()) - - -if __name__ == "__main__": - main() diff --git a/koapy/cli/__init__.py b/koapy/cli/__init__.py deleted file mode 100644 index fece6de7..00000000 --- a/koapy/cli/__init__.py +++ /dev/null @@ -1,395 +0,0 @@ -"""Console script for koapy.""" - -import os - -import click - -from koapy.cli.commands.disable import disable -from koapy.cli.commands.enable import enable -from koapy.cli.commands.generate import generate -from koapy.cli.commands.get import get -from koapy.cli.commands.install import install -from koapy.cli.commands.serve import serve -from koapy.cli.commands.show import show -from koapy.cli.commands.uninstall import uninstall -from koapy.cli.commands.update import update -from koapy.cli.utils.credentials import get_credentials -from koapy.cli.utils.fail_with_usage import fail_with_usage -from koapy.cli.utils.verbose_option import verbose_option -from koapy.config import default_encoding -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - -help_option_names = ["-h", "--help"] -context_settings = dict( - help_option_names=help_option_names, -) - - -@click.group(context_settings=context_settings) -@click.version_option(message="%(version)s") -def cli(): - pass - - -cli.add_command(disable) -cli.add_command(enable) -cli.add_command(generate) -cli.add_command(get) -cli.add_command(install) -cli.add_command(serve) -cli.add_command(show) -cli.add_command(uninstall) -cli.add_command(update) - - -@cli.command(short_help="Ensure logged in when server is up.") -@click.option( - "-i", - "--interactive", - is_flag=True, - help="Put login information with prompts. Disables auto login for manual login.", -) -@click.option( - "-d", - "--disable-auto-login", - is_flag=True, - help="Disable auto login and use credentials given explicitly from config file.", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def login(interactive, disable_auto_login, port): - credentials = get_credentials(interactive) - - from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import ( - KiwoomOpenApiPlusServiceClient, - ) - - with KiwoomOpenApiPlusServiceClient(port=port, check_timeout=1) as context: - state = context.GetConnectState() - if state == 0: - click.echo("Logging in...") - else: - click.echo("Already logged in.") - if context.IsAutoLoginEnabled(): - if not disable_auto_login: - credentials = None - context.EnsureConnected(credentials) - gubun = context.GetServerGubun() - if gubun == "1": - click.echo("Logged into Simulation server.") - else: - click.echo("Logged into Real server.") - - -@cli.command(short_help="Watch realtime data.") -@click.option( - "-c", - "--code", - "codes", - metavar="CODE", - multiple=True, - help="Stock code to get. Can set multiple times.", -) -@click.option( - "-i", - "--input", - metavar="FILENAME", - type=click.Path(), - help="Text or excel file containing codes. Alternative to --code option.", -) -@click.option( - "-f", - "--fid", - "fids", - metavar="FID", - multiple=True, - help="FID to get. Can set multiple times.", -) -@click.option( - "-t", "--realtype", metavar="REALTYPE", help="Real type name. Alternative to --fid." -) -@click.option( - "-o", - "--output", - metavar="FILENAME", - type=click.File("w", lazy=True), - default="-", - help="Output filename (optional).", -) -@click.option( - "-f", - "--format", - metavar="FORMAT", - type=click.Choice(["json", "md"], case_sensitive=False), - default="json", - help="Output format [json|md].", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def watch(codes, input, fids, realtype, output, format, port): - # pylint: disable=redefined-builtin - - if (codes, fids, realtype) == (tuple(), tuple(), None): - fail_with_usage() - - codes_len = len(codes) - - if codes_len == 0: - if input is None: - fail_with_usage("Either code or input should be given.") - if not os.path.exists(input): - fail_with_usage("Given input does not exist.") - - if os.path.isfile(input): - if input.endswith(".xlsx"): - import pandas as pd - - df = pd.read_excel(input, dtype=str) - code_column = "종목코드" - if code_column in df: - codes = df[code_column] - else: - codes = df.iloc[0] - codes_len = len(codes) - elif input.endswith(".txt"): - with open(input, "r", encoding=default_encoding) as f: - codes = [line.strip() for line in f] - codes_len = len(codes) - else: - fail_with_usage("Unrecognized input type.") - else: - fail_with_usage("Unrecognized input type.") - - if realtype is not None: - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - - fids_from_realtype = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name( - realtype - ) - fids = list(set(fids).union(set(fids_from_realtype))) - - if not codes: - fail_with_usage("No codes to watch. Set --code or --input.") - - if not fids: - fail_with_usage("Cannot infer fids to watch. Set either --fid or --realtype.") - - import datetime - - import pandas as pd - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - - def parse_message(message): - fids = message.single_data.names - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) for fid in fids - ] - values = message.single_data.values - dic = { - name: value for fid, name, value in zip(fids, names, values) if name != fid - } - series = pd.Series(dic) - return series - - if format == "json": - - def print_message(message): - click.echo(parse_message(message).to_json(), file=output) - - else: - - def print_message(message): - code = message.arguments[0].string_value - name = message.arguments[1].string_value - click.echo("[{}] [{}]".format(code, name), file=output) - click.echo("[%s]" % datetime.datetime.now(), file=output) - click.echo(parse_message(message).to_markdown(), file=output) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - for event in context.GetRealDataForCodesAsStream(codes, fids, infer_fids=True): - print_message(event) - - -order_types = [ - "1", - "2", - "3", - "4", - "5", - "6", -] - -quote_types = [ - "00", - "03", - "05", - "06", - "07", - "10", - "13", - "16", - "20", - "23", - "26", - "61", - "62", - "81", -] - - -@cli.command(short_help="Place an order.") -@click.option("--request-name", metavar="NAME") -@click.option("--screen-no", metavar="SCRNO") -@click.option("--account-no", metavar="ACCNO") -@click.option("--order-type", type=click.Choice(order_types)) -@click.option("--code", metavar="CODE") -@click.option("--quantity", metavar="QTY") -@click.option("--price", metavar="PRICE") -@click.option("--quote-type", type=click.Choice(quote_types)) -@click.option("--original-order-no", metavar="ORDERNO") -@click.option( - "-f", - "--format", - metavar="FORMAT", - type=click.Choice(["pretty", "json"], case_sensitive=False), -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def order( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - format, - port, -): - # pylint: disable=redefined-builtin - - # TODO: 주문 취소시 기존 주문에 대한 이벤트 스트림 종료되도록 - - """ - \b - [주문유형] - 1 : 신규매수 - 2 : 신규매도 - 3 : 매수취소 - 4 : 매도취소 - 5 : 매수정정 - 6 : 매도정정 - - \b - [거래구분] - 모의투자에서는 지정가 주문과 시장가 주문만 가능합니다. - 00 : 지정가 - 03 : 시장가 - 05 : 조건부지정가 - 06 : 최유리지정가 - 07 : 최우선지정가 - 10 : 지정가IOC - 13 : 시장가IOC - 16 : 최유리IOC - 20 : 지정가FOK - 23 : 시장가FOK - 26 : 최유리FOK - 61 : 장전시간외종가 - 62 : 시간외단일가매매 - 81 : 장후시간외종가 - """ - - if (request_name, screen_no, account_no, order_type, code, quantity) == ( - None, - None, - None, - None, - None, - None, - ): - fail_with_usage() - - if order_type is None: - fail_with_usage() - - from google.protobuf.json_format import MessageToDict - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - if format == "json": - import json - - def print_message(message): - click.echo(json.dumps(MessageToDict(message))) - - else: - import pprint - - pp = pprint.PrettyPrinter() - - def print_message(message): - click.echo(pp.pformat(MessageToDict(message))) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - if order_type in ["3", "4"] and (account_no is None or code is None): - for account_no_candidate in context.GetAccountList(): - df = context.GetOrderLogAsDataFrame1(account_no_candidate) - if "주문번호" in df.columns: - rows = df.loc[df["주문번호"] == original_order_no, :] - if rows.shape[0] > 0: - row = rows.iloc[0, :] - if account_no is None: - account_no = row["계좌번호"] - if code is None: - code = row["종목코드"] - break - - if account_no is None: - logger.info("Account not given. Using first account available.") - account_no = context.GetFirstAvailableAccount() - - responses = context.OrderCall( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - ) - for response in responses: - print_message(response) - - -def main(): - cli() - - -if __name__ == "__main__": - main() diff --git a/koapy/cli/__main__.py b/koapy/cli/__main__.py deleted file mode 100644 index 868d99ef..00000000 --- a/koapy/cli/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from . import main - -if __name__ == "__main__": - main() diff --git a/koapy/cli/commands/__init__.py b/koapy/cli/commands/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/commands/disable/__init__.py b/koapy/cli/commands/disable/__init__.py deleted file mode 100644 index 962bc3d4..00000000 --- a/koapy/cli/commands/disable/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from .auto_login import auto_login - - -@click.group(short_help="Disable things, including auto login.") -def disable(): - pass - - -disable.add_command(auto_login) diff --git a/koapy/cli/commands/disable/auto_login.py b/koapy/cli/commands/disable/auto_login.py deleted file mode 100644 index 67489dc5..00000000 --- a/koapy/cli/commands/disable/auto_login.py +++ /dev/null @@ -1,44 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -def disable_auto_login_after_login(port): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - context.DisableAutoLogin() - - -def disable_auto_login_without_login(): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin import ( - KiwoomOpenApiPlusQAxWidgetUniversalMixin, - ) - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - class GetAPIModulePathStub: - def GetAPIModulePath(self): - return API_MODULE_PATH - - class DisableAutoLoginStub( - GetAPIModulePathStub, - KiwoomOpenApiPlusQAxWidgetUniversalMixin, - ): - pass - - stub = DisableAutoLoginStub() - stub.DisableAutoLogin() - - -@click.command(short_help="Disable auto login.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option(default=5, show_default=True) -def auto_login(port): - disable_auto_login_without_login() diff --git a/koapy/cli/commands/enable/__init__.py b/koapy/cli/commands/enable/__init__.py deleted file mode 100644 index 88d896b4..00000000 --- a/koapy/cli/commands/enable/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from .auto_login import auto_login - - -@click.group(short_help="Enable things, including auto login.") -def enable(): - pass - - -enable.add_command(auto_login) diff --git a/koapy/cli/commands/enable/auto_login.py b/koapy/cli/commands/enable/auto_login.py deleted file mode 100644 index d02c215c..00000000 --- a/koapy/cli/commands/enable/auto_login.py +++ /dev/null @@ -1,18 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Enable auto login.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option(default=5, show_default=True) -def auto_login(port): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - context.EnsureAutoLoginEnabled() diff --git a/koapy/cli/commands/generate/__init__.py b/koapy/cli/commands/generate/__init__.py deleted file mode 100644 index 6e64e124..00000000 --- a/koapy/cli/commands/generate/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import click - -from .grpc import grpc -from .openapi import openapi - - -@click.group(short_help="Generate files related to grpc, openapi.") -def generate(): - pass - - -generate.add_command(grpc) -generate.add_command(openapi) diff --git a/koapy/cli/commands/generate/grpc/__init__.py b/koapy/cli/commands/generate/grpc/__init__.py deleted file mode 100644 index 1323892f..00000000 --- a/koapy/cli/commands/generate/grpc/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from .ssl_credentials import ssl_credentials - - -@click.group(short_help="Generate grpc related files.") -def grpc(): - pass - - -grpc.add_command(ssl_credentials) diff --git a/koapy/cli/commands/generate/grpc/ssl_credentials.py b/koapy/cli/commands/generate/grpc/ssl_credentials.py deleted file mode 100644 index ea8deefc..00000000 --- a/koapy/cli/commands/generate/grpc/ssl_credentials.py +++ /dev/null @@ -1,240 +0,0 @@ -import datetime - -import click - -from cryptography import x509 -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.x509.oid import NameOID - -from koapy.config import default_encoding - - -def generate_self_signed_key_cert( - organization_name, - common_name, - key_filename=None, - cert_filename=None, - key_password=None, - country_name=None, - state_or_province_name=None, - locality_name=None, - valid_days=None, -): - # generate root ca key - root_ca_key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - ) - encryption_algorithm = serialization.NoEncryption() - if key_password is not None: - if not isinstance(key_password, bytes): - encoding = default_encoding - key_password = key_password.encode(encoding) - encryption_algorithm = serialization.BestAvailableEncryption(key_password) - root_ca_key_bytes = root_ca_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=encryption_algorithm, - ) - if key_filename is None: - key_filename = "root_ca_key.pem" - with open(key_filename, "wb") as f: - f.write(root_ca_key_bytes) - - # generate root ca cert - name_attributes = [] - if country_name is not None: - name_attributes.append(x509.NameAttribute(NameOID.COUNTRY_NAME, country_name)) - if state_or_province_name is not None: - name_attributes.append( - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state_or_province_name) - ) - if locality_name is not None: - name_attributes.append(x509.NameAttribute(NameOID.LOCALITY_NAME, locality_name)) - name_attributes += [ - x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization_name), - x509.NameAttribute(NameOID.COMMON_NAME, common_name), - ] - subject = issuer = x509.Name(name_attributes) - cert_builder = x509.CertificateBuilder() - cert_builder = cert_builder.subject_name(subject) - cert_builder = cert_builder.issuer_name(issuer) - cert_builder = cert_builder.public_key(root_ca_key.public_key()) - cert_builder = cert_builder.serial_number(x509.random_serial_number()) - if valid_days is None: - valid_days = 356 * 10 - not_valid_before = datetime.datetime.utcnow() - not_valid_after = not_valid_before + datetime.timedelta(days=valid_days) - cert_builder = cert_builder.not_valid_before(not_valid_before) - cert_builder = cert_builder.not_valid_after(not_valid_after) - cert_builder = cert_builder.add_extension( - x509.SubjectAlternativeName([x509.DNSName("localhost")]), - critical=False, - ) - root_ca_cert = cert_builder.sign(root_ca_key, hashes.SHA256()) - root_ca_cert_bytes = root_ca_cert.public_bytes(serialization.Encoding.PEM) - if cert_filename is None: - cert_filename = "root_ca_cert.pem" - with open(cert_filename, "wb") as f: - f.write(root_ca_cert_bytes) - - -def generate_key_cert_signed_by_authority( - organization_name, - common_name, - alternative_dns_names=None, - key_filename=None, - csr_filename=None, - cert_filename=None, - key_password=None, - country_name=None, - state_or_province_name=None, - locality_name=None, - valid_days=None, - authority_key_filename=None, - authority_cert_filename=None, - authority_key_password=None, -): - # generate server key - key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - ) - encryption_algorithm = serialization.NoEncryption() - if key_password is not None: - if not isinstance(key_password, bytes): - encoding = default_encoding - key_password = key_password.encode(encoding) - encryption_algorithm = serialization.BestAvailableEncryption(key_password) - key_bytes = key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=encryption_algorithm, - ) - if key_filename is None: - key_filename = "key.pem" - with open(key_filename, "wb") as f: - f.write(key_bytes) - - # generate server csr - name_attributes = [] - if country_name is not None: - name_attributes.append(x509.NameAttribute(NameOID.COUNTRY_NAME, country_name)) - if state_or_province_name is not None: - name_attributes.append( - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state_or_province_name) - ) - if locality_name is not None: - name_attributes.append(x509.NameAttribute(NameOID.LOCALITY_NAME, locality_name)) - name_attributes += [ - x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization_name), - x509.NameAttribute(NameOID.COMMON_NAME, common_name), - ] - subject = x509.Name(name_attributes) - csr_builder = x509.CertificateSigningRequestBuilder() - csr_builder = csr_builder.subject_name(subject) - if alternative_dns_names is None: - alternative_dns_names = ["localhost"] - csr_builder = csr_builder.add_extension( - x509.SubjectAlternativeName( - [x509.DNSName(name) for name in alternative_dns_names] - ), - critical=False, - ) - csr = csr_builder.sign(key, hashes.SHA256()) - csr_bytes = csr.public_bytes(serialization.Encoding.PEM) - if csr_filename is None: - csr_filename = "csr.pem" - with open(csr_filename, "wb") as f: - f.write(csr_bytes) - - # get authority key and cert - if authority_key_password is not None: - if not isinstance(authority_key_password, bytes): - encoding = default_encoding - authority_key_password = authority_key_password.encode(encoding) - if authority_key_filename is None: - authority_key_filename = "root_ca_key.pem" - with open(authority_key_filename, "rb") as f: - authority_key = serialization.load_pem_private_key( - f.read(), - password=authority_key_password, - ) - if authority_cert_filename is None: - authority_cert_filename = "root_ca_cert.pem" - with open(authority_cert_filename, "rb") as f: - authority_cert = x509.load_pem_x509_certificate(f.read()) - - # root ca signs and issues server cert from server csr - cert_builder = x509.CertificateBuilder() - cert_builder = cert_builder.subject_name(subject) - cert_builder = cert_builder.issuer_name(authority_cert.subject) - cert_builder = cert_builder.public_key(csr.public_key()) - cert_builder = cert_builder.serial_number(x509.random_serial_number()) - if valid_days is None: - valid_days = 356 - not_valid_before = datetime.datetime.utcnow() - not_valid_after = not_valid_before + datetime.timedelta(days=valid_days) - cert_builder = cert_builder.not_valid_before(not_valid_before) - cert_builder = cert_builder.not_valid_after(not_valid_after) - for extension in csr.extensions: - cert_builder = cert_builder.add_extension( - extension.value, - critical=extension.critical, - ) - cert = cert_builder.sign(authority_key, hashes.SHA256()) - cert_bytes = cert.public_bytes(serialization.Encoding.PEM) - if cert_filename is None: - cert_filename = "cert.pem" - with open(cert_filename, "wb") as f: - f.write(cert_bytes) - - -@click.command( - short_help="Generate crypto-related files for server/client SSL/TLS.", -) -def ssl_credentials(): - # generate root ca key and cert - root_ca_organization_name = "Root CA" - root_ca_common_name = "localhost" - root_ca_key_filename = "root_ca_key.pem" - root_ca_cert_filename = "root_ca_cert.pem" - generate_self_signed_key_cert( - root_ca_organization_name, - root_ca_common_name, - key_filename=root_ca_key_filename, - cert_filename=root_ca_cert_filename, - ) - - # generate server key and cert - server_organization_name = "Server" - server_common_name = "localhost" - server_key_filename = "server_key.pem" - server_csr_filename = "server_csr.pem" - server_cert_filename = "server_cert.pem" - generate_key_cert_signed_by_authority( - server_organization_name, - server_common_name, - key_filename=server_key_filename, - csr_filename=server_csr_filename, - cert_filename=server_cert_filename, - authority_key_filename=root_ca_key_filename, - authority_cert_filename=root_ca_cert_filename, - ) - - # generate client key and cert - client_organization_name = "Client" - client_common_name = "localhost" - client_key_filename = "client_key.pem" - client_csr_filename = "client_csr.pem" - client_cert_filename = "client_cert.pem" - generate_key_cert_signed_by_authority( - client_organization_name, - client_common_name, - key_filename=client_key_filename, - csr_filename=client_csr_filename, - cert_filename=client_cert_filename, - authority_key_filename=root_ca_key_filename, - authority_cert_filename=root_ca_cert_filename, - ) diff --git a/koapy/cli/commands/generate/openapi/__init__.py b/koapy/cli/commands/generate/openapi/__init__.py deleted file mode 100644 index 1e019e0d..00000000 --- a/koapy/cli/commands/generate/openapi/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from .python_stubs import python_stubs - - -@click.group(short_help="Generate openapi related files.") -def openapi(): - pass - - -openapi.add_command(python_stubs) diff --git a/koapy/cli/commands/generate/openapi/python_stubs.py b/koapy/cli/commands/generate/openapi/python_stubs.py deleted file mode 100644 index 08da8a12..00000000 --- a/koapy/cli/commands/generate/openapi/python_stubs.py +++ /dev/null @@ -1,74 +0,0 @@ -import click - -from koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs import ( - generate_python_stubs, -) -from koapy.config import default_encoding - -default_dispatch_class_name = "KiwoomOpenApiPlusDispatchFunctionsGenerated" -default_dispatch_file_path = default_dispatch_class_name + ".py" - -default_event_class_name = "KiwoomOpenApiPlusEventFunctionsGenerated" -default_event_file_path = default_event_class_name + ".py" - - -@click.command( - short_help="Generate python stubs for OpenAPI Dispatch and Event.", -) -@click.option( - "--dispatch-class-name", - metavar="NAME", - help="Name for class with Dispatch functions.", - default=default_dispatch_class_name, - show_default=True, -) -@click.option( - "--dispatch-file-path", - type=click.Path(), - help="Path for python-stub with Dispatch functions.", - default=default_dispatch_file_path, - show_default=True, -) -@click.option( - "--event-class-name", - metavar="NAME", - help="Name for class with Event functions.", - default=default_event_class_name, - show_default=True, -) -@click.option( - "--event-file-path", - type=click.Path(), - help="Path for python-stub with Event functions.", - default=default_event_file_path, - show_default=True, -) -@click.option( - "--encoding", - metavar="ENCODING", - help="Encoding for stub files.", - default=default_encoding, - show_default=True, -) -@click.option( - "--force-overwrite", - help="Force overwrite even if target file already exists.", - is_flag=True, - show_default=True, -) -def python_stubs( - dispatch_class_name, - dispatch_file_path, - event_class_name, - event_file_path, - encoding, - force_overwrite, -): - generate_python_stubs( - dispatch_class_name=dispatch_class_name, - dispatch_file_path=dispatch_file_path, - event_class_name=event_class_name, - event_file_path=event_file_path, - encoding=encoding, - force_overwrite=force_overwrite, - ) diff --git a/koapy/cli/commands/get/__init__.py b/koapy/cli/commands/get/__init__.py deleted file mode 100644 index ce8f605a..00000000 --- a/koapy/cli/commands/get/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -import click - -from .account_data.deposit import deposit -from .account_data.evaluation import evaluation -from .account_data.orders import orders -from .account_data.userinfo import userinfo -from .chart_data.daily import daily -from .chart_data.minute import minute -from .openapi_meta.errmsg import errmsg -from .openapi_meta.modulepath import modulepath -from .openapi_meta.realinfo import realinfo -from .openapi_meta.trinfo import trinfo -from .stock_meta.codelist import codelist -from .stock_meta.stockcode import stockcode -from .stock_meta.stockinfo import stockinfo -from .stock_meta.stockname import stockname - - -@click.group(short_help="Get various types of data.") -def get(): - pass - - -get.add_command(deposit) -get.add_command(evaluation) -get.add_command(orders) -get.add_command(userinfo) - -get.add_command(daily) -get.add_command(minute) - -get.add_command(errmsg) -get.add_command(modulepath) -get.add_command(realinfo) -get.add_command(trinfo) - -get.add_command(codelist) -get.add_command(stockcode) -get.add_command(stockinfo) -get.add_command(stockname) diff --git a/koapy/cli/commands/get/account_data/__init__.py b/koapy/cli/commands/get/account_data/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/commands/get/account_data/deposit.py b/koapy/cli/commands/get/account_data/deposit.py deleted file mode 100644 index e561ffe4..00000000 --- a/koapy/cli/commands/get/account_data/deposit.py +++ /dev/null @@ -1,30 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Get account deposit.") -@click.option("-a", "--account", metavar="ACCNO", help="Account number.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def deposit(account, port): - if account is None: - logger.info("Account not given. Using first account available.") - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - if account is None: - account = context.GetAccountList()[0] - - result = context.GetDepositInfo(account) - click.echo(result.to_markdown(floatfmt=".2f")) diff --git a/koapy/cli/commands/get/account_data/evaluation.py b/koapy/cli/commands/get/account_data/evaluation.py deleted file mode 100644 index 8a14b3e5..00000000 --- a/koapy/cli/commands/get/account_data/evaluation.py +++ /dev/null @@ -1,63 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Get account evaluation.") -@click.option("-a", "--account", metavar="ACCNO", help="Account number.") -@click.option( - "-d", "--include-delisted", is_flag=True, help="Include delisted.", default=True -) -@click.option("-D", "--exclude-delisted", is_flag=True, help="Exclude delisted.") -@click.option( - "-e", "--for-each", is_flag=True, help="Show individual evaluation.", default=True -) -@click.option("-E", "--as-summary", is_flag=True, help="Show summarized evaluation.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def evaluation(account, include_delisted, exclude_delisted, for_each, as_summary, port): - if account is None: - logger.info("Account not given. Using first account available.") - - if exclude_delisted: - include_delisted = False - - if as_summary: - for_each = False - lookup_type = "1" - elif for_each: - lookup_type = "2" - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - if account is None: - account = context.GetAccountList()[0] - - single, multi = context.GetAccountEvaluationStatusAsSeriesAndDataFrame( - account, include_delisted - ) - click.echo("[계좌평가현황요청] : [계좌평가현황]") - click.echo(single.to_markdown(floatfmt=".2f")) - click.echo() - click.echo("[계좌평가현황요청] : [종목별계좌평가현황]") - click.echo(multi.to_markdown()) - click.echo() - - single, multi = context.GetAccountEvaluationBalanceAsSeriesAndDataFrame( - account, lookup_type - ) - click.echo("[계좌평가잔고내역요청] : [계좌평가결과]") - click.echo(single.to_markdown(floatfmt=".2f")) - click.echo() - click.echo("[계좌평가잔고내역요청] : [계좌평가잔고개별합산]") - click.echo(multi.to_markdown()) diff --git a/koapy/cli/commands/get/account_data/orders.py b/koapy/cli/commands/get/account_data/orders.py deleted file mode 100644 index 527952f1..00000000 --- a/koapy/cli/commands/get/account_data/orders.py +++ /dev/null @@ -1,80 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Get order history of a date.") -@click.option("-a", "--account", metavar="ACCNO", help="Account number.") -@click.option("-d", "--date", metavar="DATE", help="Date to get.") -@click.option("-r", "--reverse", is_flag=True) -@click.option("-e", "--executed-only", is_flag=True) -@click.option("-E", "--not-executed-only", is_flag=True) -@click.option("-S", "--stock-only", is_flag=True) -@click.option("-B", "--bond-only", is_flag=True) -@click.option("-s", "--sell-only", is_flag=True) -@click.option("-b", "--buy-only", is_flag=True) -@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") -@click.option("-o", "--starting-order-no", metavar="ORDERNO", help="Starting order no.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def orders( - account, - date, - reverse, - executed_only, - not_executed_only, - stock_only, - bond_only, - sell_only, - buy_only, - code, - starting_order_no, - port, -): - if account is None: - logger.info("Account not given. Using first account available.") - - sort_type = "1" - if reverse: - sort_type = "2" - if executed_only: - sort_type = "3" - if not_executed_only: - sort_type = "4" - asset_type = "0" - if stock_only: - asset_type = "1" - if bond_only: - asset_type = "2" - order_type = "0" - if sell_only: - order_type = "1" - if buy_only: - order_type = "2" - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - if account is None: - account = context.GetFirstAvailableAccount() - df = context.GetOrderLogAsDataFrame1(account) - click.echo("[실시간미체결요청]") - click.echo(df.to_markdown()) - click.echo() - df = context.GetOrderLogAsDataFrame2(account) - click.echo("[실시간체결요청]") - click.echo(df.to_markdown()) - click.echo() - df = context.GetOrderLogAsDataFrame3( - account, date, sort_type, asset_type, order_type, code, starting_order_no - ) - click.echo("[계좌별주문체결내역상세요청]") - click.echo(df.to_markdown()) diff --git a/koapy/cli/commands/get/account_data/userinfo.py b/koapy/cli/commands/get/account_data/userinfo.py deleted file mode 100644 index 98848831..00000000 --- a/koapy/cli/commands/get/account_data/userinfo.py +++ /dev/null @@ -1,41 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get user information.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def userinfo(port): - import pandas as pd - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - result = {} - result["보유계좌수"] = context.GetLoginInfo("ACCOUNT_CNT") - account_numbers = context.GetLoginInfo("ACCLIST").rstrip(";").split(";") - for i, accno in enumerate(account_numbers): - result["계좌번호 (%d/%s)" % (i + 1, result["보유계좌수"])] = accno - result["사용자 ID"] = context.GetLoginInfo("USER_ID") - result["사용자 명"] = context.GetLoginInfo("USER_NAME") - result["키보드보안 해지 여부"] = { - "0": "정상", - "1": "해지", - }.get(context.GetLoginInfo("KEY_BSECGB"), "알수없음") - result["방화벽 설정 여부"] = { - "0": "미설정", - "1": "설정", - "2": "해지", - }.get(context.GetLoginInfo("FIREW_SECGB"), "알수없음") - result["접속서버 구분"] = { - "1": "모의투자", - }.get(context.GetServerGubun(), "실서버") - - click.echo(pd.Series(result).to_markdown()) diff --git a/koapy/cli/commands/get/chart_data/__init__.py b/koapy/cli/commands/get/chart_data/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/commands/get/chart_data/daily.py b/koapy/cli/commands/get/chart_data/daily.py deleted file mode 100644 index c42a7a2e..00000000 --- a/koapy/cli/commands/get/chart_data/daily.py +++ /dev/null @@ -1,71 +0,0 @@ -import click - -from koapy.cli.utils.fail_with_usage import fail_with_usage -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Get daily OHLCV of stocks.") -@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") -@click.option( - "-o", - "--output", - metavar="FILENAME", - type=click.Path(), - help="Output filename for code.", -) -@click.option( - "-f", - "--format", - metavar="FORMAT", - type=click.Choice(["xlsx", "sqlite3"], case_sensitive=False), - default="xlsx", - help="Output format. (default: xlsx)", -) -@click.option( - "-s", - "--start-date", - metavar="YYYY-MM-DD", - type=click.DateTime(formats=["%Y-%m-%d", "%Y%m%d"]), - help="Most recent date to get. Defaults to today or yesterday if market is open.", -) -@click.option( - "-e", - "--end-date", - metavar="YYYY-MM-DD", - type=click.DateTime(formats=["%Y-%m-%d", "%Y%m%d"]), - help="Stops if reached, not included (optional).", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def daily( - code, output, format, start_date, end_date, port -): # pylint: disable=redefined-builtin - if (code, output, start_date, end_date) == (None, None, None, None): - fail_with_usage() - - if output is None: - output = "{}.{}".format(code, format) - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - df = context.GetDailyStockDataAsDataFrame(code, start_date, end_date) - - if format == "xlsx": - df.to_excel(output) - logger.info("Saved data to file: %s", output) - elif format == "sqlite3": - from sqlalchemy import create_engine - - engine = create_engine("sqlite:///" + output) - tablename = "A" + code - df.to_sql(tablename, engine) - logger.info("Saved data to file %s with tablename %s", output, tablename) diff --git a/koapy/cli/commands/get/chart_data/minute.py b/koapy/cli/commands/get/chart_data/minute.py deleted file mode 100644 index 6978b958..00000000 --- a/koapy/cli/commands/get/chart_data/minute.py +++ /dev/null @@ -1,96 +0,0 @@ -import click - -from koapy.cli.utils.fail_with_usage import fail_with_usage -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - -minute_intervals = [ - "1", - "3", - "5", - "10", - "15", - "30", - "45", - "60", -] - - -@click.command(short_help="Get minute OHLCV of stocks.") -@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") -@click.option( - "-t", - "--interval", - metavar="INTERVAL", - type=click.Choice(minute_intervals, case_sensitive=False), - help="Minute interval. Possible values are [%s]" % "|".join(minute_intervals), -) -@click.option( - "-o", - "--output", - metavar="FILENAME", - type=click.Path(), - help="Output filename for code.", -) -@click.option( - "-f", - "--format", - metavar="FORMAT", - type=click.Choice(["xlsx", "sqlite3"], case_sensitive=False), - default="xlsx", - help="Output format. (default: xlsx)", -) -@click.option( - "-s", - "--start-date", - metavar="YYYY-MM-DD['T'hh:mm:ss]", - type=click.DateTime( - formats=["%Y-%m-%d", "%Y%m%d", "%Y-%m-%dT%H:%M:%S", "%Y%m%d%H%M%S"] - ), - help="Most recent date to get. Defaults to today or yesterday if market is open.", -) -@click.option( - "-e", - "--end-date", - metavar="YYYY-MM-DD['T'hh:mm:ss]", - type=click.DateTime( - formats=["%Y-%m-%d", "%Y%m%d", "%Y-%m-%dT%H:%M:%S", "%Y%m%d%H%M%S"] - ), - help="Stops if reached, not included (optional).", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def minute( - code, interval, output, format, start_date, end_date, port -): # pylint: disable=redefined-builtin - if (code, interval, output, start_date, end_date) == (None, None, None, None, None): - fail_with_usage() - - if interval is None: - fail_with_usage("Interval is not set.") - - if output is None: - output = "{}.{}".format(code, format) - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - df = context.GetMinuteStockDataAsDataFrame(code, interval, start_date, end_date) - - if format == "xlsx": - df.to_excel(output) - logger.info("Saved data to file: %s", output) - elif format == "sqlite3": - from sqlalchemy import create_engine - - engine = create_engine("sqlite:///" + output) - tablename = "A" + code - df.to_sql(tablename, engine) - logger.info("Saved data to file %s with tablename %s", output, tablename) diff --git a/koapy/cli/commands/get/openapi_meta/__init__.py b/koapy/cli/commands/get/openapi_meta/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/commands/get/openapi_meta/errmsg.py b/koapy/cli/commands/get/openapi_meta/errmsg.py deleted file mode 100644 index c54c471d..00000000 --- a/koapy/cli/commands/get/openapi_meta/errmsg.py +++ /dev/null @@ -1,19 +0,0 @@ -import click - -from koapy.cli.utils.fail_with_usage import fail_with_usage -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get error message for error code.") -@click.option("-e", "--err-code", metavar="ERR", type=int, help="Error code to check.") -@verbose_option() -def errmsg(err_code): - if err_code is None: - fail_with_usage() - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError import ( - KiwoomOpenApiPlusError, - ) - - err_msg = KiwoomOpenApiPlusError.get_error_message_by_code(err_code) - click.echo("[%d] %s" % (err_code, err_msg)) diff --git a/koapy/cli/commands/get/openapi_meta/modulepath.py b/koapy/cli/commands/get/openapi_meta/modulepath.py deleted file mode 100644 index 83b543ce..00000000 --- a/koapy/cli/commands/get/openapi_meta/modulepath.py +++ /dev/null @@ -1,13 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get OpenApi module installation path.") -@verbose_option() -def modulepath(): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, - ) - - click.echo(API_MODULE_PATH) diff --git a/koapy/cli/commands/get/openapi_meta/realinfo.py b/koapy/cli/commands/get/openapi_meta/realinfo.py deleted file mode 100644 index 5f72b11c..00000000 --- a/koapy/cli/commands/get/openapi_meta/realinfo.py +++ /dev/null @@ -1,52 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get real type info.") -@click.option( - "-t", - "--realtype", - "realtypes", - metavar="REALTYPE", - multiple=True, - help="Real type name to get (like 주식시세).", -) -@verbose_option() -def realinfo(realtypes): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - - def get_realtypes(): - if realtypes: - if "-" in realtypes: - with click.open_file("-", "r") as f: - for realtype in f: - yield realtype.strip() - else: - for realtype in realtypes: - yield realtype - else: - while True: - try: - realtype = click.prompt("realtype", prompt_suffix=" >>> ") - realtype = realtype.strip() - if realtype == "exit": - break - if realtype: - yield realtype - except EOFError: - break - - for realtype in get_realtypes(): - fids = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype) - if fids: - names = [ - KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(fid, str(fid)) - for fid in fids - ] - for fid, name in zip(fids, names): - click.echo(" [{}] = {}".format(fid, name)) - else: - click.echo("Given realtype is invalid") diff --git a/koapy/cli/commands/get/openapi_meta/trinfo.py b/koapy/cli/commands/get/openapi_meta/trinfo.py deleted file mode 100644 index b920fe34..00000000 --- a/koapy/cli/commands/get/openapi_meta/trinfo.py +++ /dev/null @@ -1,62 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get TR info.") -@click.option( - "-t", - "--trcode", - "trcodes", - metavar="TRCODE", - multiple=True, - help="TR code to get (like opt10001).", -) -@verbose_option() -def trinfo(trcodes): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, - ) - - def get_codes(): - if trcodes: - if "-" in trcodes: - with click.open_file("-", "r") as f: - for code in f: - yield code.strip() - else: - for code in trcodes: - yield code - else: - while True: - try: - code = click.prompt("trcode", prompt_suffix=" >>> ") - code = code.strip() - if code == "exit": - break - if code: - yield code - except EOFError: - break - - for trcode in get_codes(): - tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(trcode) - if tr_info is not None: - click.echo("[{}] : [{}]".format(tr_info.tr_code.upper(), tr_info.name)) - click.echo(" [INPUT]") - for tr_input in tr_info.inputs: - click.echo(" %s" % tr_input.name) - if tr_info.single_outputs: - click.echo( - " [OUTPUT] [SINGLE DATA] : [%s]" % tr_info.single_outputs_name - ) - for output in tr_info.single_outputs: - click.echo(" %s" % output.name) - if tr_info.multi_outputs: - click.echo( - " [OUTPUT] [MULTI DATA] : [%s]" % tr_info.multi_outputs_name - ) - for output in tr_info.multi_outputs: - click.echo(" %s" % output.name) - else: - click.echo("Given trcode is invalid") diff --git a/koapy/cli/commands/get/stock_meta/__init__.py b/koapy/cli/commands/get/stock_meta/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/commands/get/stock_meta/codelist.py b/koapy/cli/commands/get/stock_meta/codelist.py deleted file mode 100644 index 6027ab09..00000000 --- a/koapy/cli/commands/get/stock_meta/codelist.py +++ /dev/null @@ -1,73 +0,0 @@ -import click - -from koapy.cli.commands.get.stock_meta.codelist_interactive import codelist_interactive -from koapy.cli.utils.verbose_option import verbose_option - -market_codes = [ - "0", - "10", - "3", - "8", - "50", - "4", - "5", - "6", - "9", - "30", - "all", -] - - -@click.command(short_help="Get stock codes.") -@click.option( - "-m", - "--market", - "markets", - metavar="MARKET", - multiple=True, - type=click.Choice(market_codes, case_sensitive=False), - help="Stock market code to get. Can set multiple times.", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def codelist(markets, port): - """ - \b - Possible market codes are: - 0 : 장내 - 10 : 코스닥 - 3 : ELW - 8 : ETF - 50 : KONEX - 4 : 뮤추얼펀드 - 5 : 신주인수권 - 6 : 리츠 - 9 : 하이얼펀드 - 30 : K-OTC - """ - - if not markets and click.get_text_stream("stdin").isatty(): - return codelist_interactive() - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - codes = set() - for market in markets: - codes = codes.union(set(context.GetCodeListByMarketAsList(market))) - codes = sorted(list(codes)) - for code in codes: - click.echo(code) - - -def main(): - codelist() # pylint: disable=no-value-for-parameter - - -if __name__ == "__main__": - main() diff --git a/koapy/cli/commands/get/stock_meta/codelist_interactive.py b/koapy/cli/commands/get/stock_meta/codelist_interactive.py deleted file mode 100644 index 8678007f..00000000 --- a/koapy/cli/commands/get/stock_meta/codelist_interactive.py +++ /dev/null @@ -1,241 +0,0 @@ -import curses -import curses.ascii -import logging -import unicodedata - -import pygtrie - -from koapy.utils.logging.Logging import Logging - - -class MarketEntry: - def __init__(self, code, name): - self.code = code - self.name = name - self.stocks = [] - - def to_string(self): - return "[{:2}] {}".format(self.code, self.name) - - -class StockEntry: - def __init__(self, code, name): - self.code = code - self.name = name - - def to_string(self): - return "[{}] {}".format(self.code, self.name) - - -markets = [ - MarketEntry(0, "KOSPI"), - MarketEntry(10, "KOSDAQ"), - MarketEntry(3, "ELW"), - MarketEntry(8, "ETF"), - MarketEntry(50, "KONEX"), - MarketEntry(4, "MUTUAL FUND"), - MarketEntry(5, "RIGHTS OFFERING"), - MarketEntry(6, "REITS"), - MarketEntry(9, "HIGH YIELD FUND"), - MarketEntry(30, "K-OTC"), -] - - -class StatusBarHandler(logging.Handler): - def __init__(self, screen, level=logging.NOTSET): - super().__init__(level) - self._screen = screen - - def emit(self, record): - self._screen.set_footer_bar(record.getMessage()) - - -def screen_len(str): - l = 0 - for c in str: - if unicodedata.east_asian_width(c) in ["F", "W"]: - l += 2 - else: - l += 1 - return l - - -class Screen: - def __init__(self, screen): - self._screen = screen - - curses.start_color() - curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) - - self._screen.clear() - self._screen.refresh() - - self._height, self._width = self._screen.getmaxyx() - - self._header_bar = curses.newwin(1, self._width, 0, 0) - self._header_bar.attron(curses.A_REVERSE) - self._header_bar_prefix = ">>> " - self._header_bar_text = self._header_bar_prefix - self._pad = curses.newpad(0, self._width) - self._footer_bar = curses.newwin(1, self._width, self._height - 1, 0) - self._footer_bar.attron(curses.A_REVERSE) - self._footer_text = "" - - self._exit_key = ord("q") - - self.refresh_header_bar() - self.set_footer_bar("Logs will appear here...") - - self._handler = StatusBarHandler(self) - self._logger = Logging.get_logger("koapy") - self._logger.addHandler(self._handler) - - from koapy import KiwoomOpenApiPlusEntrypoint - - self._entrypoint = KiwoomOpenApiPlusEntrypoint() - self._entrypoint.EnsureConnected() - - def refresh_header_bar(self): - self._height, self._width = self._screen.getmaxyx() - self._header_bar.resize(1, self._width) - self._header_bar.mvwin(0, 0) - self._header_bar.addstr(0, 0, self._header_bar_text.ljust(self._width - 1)) - self._screen.move(0, screen_len(self._header_bar_text)) - self._header_bar.refresh() - - def set_header_bar(self, text): - self._header_bar_text = self._header_bar_prefix + text - self.refresh_header_bar() - - def refresh_footer_bar(self): - self._height, self._width = self._screen.getmaxyx() - self._footer_bar.resize(1, self._width) - self._footer_bar.mvwin(self._height - 1, 0) - self._footer_bar.addstr(0, 0, self._footer_text.ljust(self._width - 1)) - self._footer_bar.refresh() - - def set_footer_bar(self, text): - self._footer_text = text - self.refresh_footer_bar() - - def show_entries(self, entries): - trie = pygtrie.CharTrie() - for entry in entries: - trie[str(entry.code)] = entry - trie[entry.name] = entry - original_entries = entries - current_entries = original_entries - k = 0 - cursor_y = 0 - scroll_y = 0 - query = "" - while k not in [curses.ascii.ESC, curses.KEY_LEFT]: - self.set_header_bar(query) - self.refresh_footer_bar() - self._height, self._width = self._screen.getmaxyx() - pad_height = self._height - 2 - pad_width = self._width - self._pad.resize(len(current_entries), pad_width) - self._pad.clear() - if k == curses.KEY_DOWN: - cursor_y = cursor_y + 1 - elif k == curses.KEY_UP: - cursor_y = cursor_y - 1 - elif k == curses.KEY_PPAGE: - prev_scroll_y = scroll_y - scroll_y = max(scroll_y - pad_height, 0) - cursor_y -= prev_scroll_y - scroll_y - elif k == curses.KEY_NPAGE: - prev_scroll_y = scroll_y - scroll_y = min( - scroll_y + pad_height, len(current_entries) - 1 - pad_height - ) - scroll_y = max(0, scroll_y) - cursor_y += scroll_y - prev_scroll_y - elif k == curses.KEY_RIGHT: - if len(current_entries) > 0: - entry = current_entries[cursor_y] - if hasattr(entry, "stocks"): - market = entry - if len(market.stocks) == 0: - stock_codes = self._entrypoint.GetCodeListByMarketAsList( - market.code - ) - stock_names = [ - self._entrypoint.GetMasterCodeName(code) - for code in stock_codes - ] - stocks = [ - StockEntry(code, name) - for code, name in zip(stock_codes, stock_names) - ] - market.stocks = stocks - self._pad.clear() - self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) - self.show_entries(market.stocks) - self._pad.clear() - self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) - k = 0 - continue - elif k in [curses.KEY_BACKSPACE, 8]: - if len(query) > 0: - query = query[:-1] - self.set_header_bar(query) - if len(query) > 0: - if trie.has_key(query) or trie.has_subtrie(query): - current_entries = trie.values(query) - else: - current_entries = original_entries - self._pad.clear() - self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) - k = 0 - continue - elif unicodedata.category(chr(k))[0] != "C": - query += chr(k) - self.set_header_bar(query) - if trie.has_key(query) or trie.has_subtrie(query): - current_entries = trie.values(query) - else: - current_entries = [] - self._pad.clear() - self._pad.refresh(0, 0, 1, 0, pad_height, pad_width - 1) - k = 0 - continue - cursor_y = min(len(current_entries) - 1, cursor_y) - cursor_y = max(0, cursor_y) - if k == curses.KEY_DOWN: - if cursor_y == (scroll_y + pad_height - 9): - scroll_y = cursor_y - pad_height + 10 - elif cursor_y > (scroll_y + pad_height - 2): - scroll_y = cursor_y - pad_height + 1 - elif k == curses.KEY_UP: - if cursor_y == scroll_y + 8: - scroll_y = cursor_y - 9 - elif cursor_y < scroll_y: - scroll_y = cursor_y - scroll_y = min(len(current_entries) - 1, scroll_y) - scroll_y = max(0, scroll_y) - for i, market in enumerate(current_entries): - attr = 0 - if i == cursor_y: - attr = curses.A_UNDERLINE - self._pad.addstr(i, 0, market.to_string().ljust(pad_width - 1), attr) - self._pad.refresh(scroll_y, 0, 1, 0, pad_height, pad_width - 1) - k = self._screen.getch() - - -def wrapper(stdscr): - screen = Screen(stdscr) - screen.show_entries(markets) - - -def codelist_interactive(): - curses.wrapper(wrapper) - - -def main(): - codelist_interactive() - - -if __name__ == "__main__": - main() diff --git a/koapy/cli/commands/get/stock_meta/stockcode.py b/koapy/cli/commands/get/stock_meta/stockcode.py deleted file mode 100644 index ae89f87d..00000000 --- a/koapy/cli/commands/get/stock_meta/stockcode.py +++ /dev/null @@ -1,111 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - -market_codes = [ - "0", - "10", - "3", - "8", - "50", - "4", - "5", - "6", - "9", - "30", - "all", -] - - -@click.command(short_help="Get stock codes.") -@click.option( - "-n", - "--name", - "names", - metavar="NAME", - multiple=True, - help="Name of stock. Can set multiple times.", -) -@click.option( - "-m", - "--market", - "markets", - metavar="MARKET", - multiple=True, - type=click.Choice(market_codes, case_sensitive=False), - help="Stock market code to get. Can set multiple times.", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def stockcode(names, markets, port): - """ - \b - Possible market codes are: - 0 : 장내 - 10 : 코스닥 - 3 : ELW - 8 : ETF - 50 : KONEX - 4 : 뮤추얼펀드 - 5 : 신주인수권 - 6 : 리츠 - 9 : 하이얼펀드 - 30 : K-OTC - """ - - markets_option = markets - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - if not markets: - markets = ["0"] - - codes = set() - - for market in markets: - codes = codes.union(set(context.GetCodeListByMarketAsList(market))) - - codes = sorted(list(codes)) - - if markets_option: - for code in codes: - click.echo(code) - else: - - def get_names(): - if names: - if "-" in names: - with click.open_file("-", "r") as f: - for name in f: - yield name.strip() - else: - for name in names: - yield name - else: - while True: - try: - name = click.prompt("name", prompt_suffix=" >>> ") - name = name.strip() - if name == "exit": - break - if name: - yield name - except EOFError: - break - - all_names = [context.GetMasterCodeName(code) for code in codes] - codes_by_name = dict(zip(all_names, codes)) - - for name in get_names(): - code = codes_by_name.get(name, None) - if code: - click.echo(code) - else: - click.echo("Cannot find code for given name: %s." % name) diff --git a/koapy/cli/commands/get/stock_meta/stockinfo.py b/koapy/cli/commands/get/stock_meta/stockinfo.py deleted file mode 100644 index c530d247..00000000 --- a/koapy/cli/commands/get/stock_meta/stockinfo.py +++ /dev/null @@ -1,70 +0,0 @@ -import click - -from koapy.cli.utils.fail_with_usage import fail_with_usage -from koapy.cli.utils.verbose_option import verbose_option -from koapy.config import default_encoding - - -@click.command(short_help="Get basic information of stocks.") -@click.option("-c", "--code", metavar="CODE", help="Stock code to get.") -@click.option( - "-o", - "--output", - metavar="FILENAME", - type=click.Path(), - help="Output filename. Optional for single code (prints to console).", -) -@click.option( - "-f", - "--format", - type=click.Choice(["md", "xlsx", "json"], case_sensitive=False), - help="Output format. (default: md)", - default="md", - show_choices=True, -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def stockinfo(code, output, format, port): # pylint: disable=redefined-builtin - if (code, output) == (None, None): - fail_with_usage() - - if output is None: - if format is None: - format = "md" - else: - if format is None: - format = "xlsx" - if format == "xlsx": - if not output.endswith(".xlsx"): - output += ".xlsx" - elif format == "md": - if not output.endswith(".md"): - output += ".md" - elif format == "json": - if not output.endswith(".json"): - output += ".json" - - import pandas as pd - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - dic = context.GetStockBasicInfoAsDict(code) - series = pd.Series(dic) - - if not output: - if format == "md": - click.echo(series.to_markdown()) - elif format == "json": - click.echo(series.to_json()) - else: - if format == "xlsx": - series.to_excel(output, header=False) - elif format == "json": - with open(output, "w", encoding=default_encoding) as f: - click.echo(series.to_json(), file=f) diff --git a/koapy/cli/commands/get/stock_meta/stockname.py b/koapy/cli/commands/get/stock_meta/stockname.py deleted file mode 100644 index a3c4bd02..00000000 --- a/koapy/cli/commands/get/stock_meta/stockname.py +++ /dev/null @@ -1,50 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Get name for stock codes.") -@click.option( - "-c", - "--code", - "codes", - metavar="CODE", - multiple=True, - help="Stock code to get. Can set multiple times.", -) -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def stockname(codes, port): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - - def get_codes(): - if codes: - if "-" in codes: - with click.open_file("-", "r") as f: - for code in f: - yield code.strip() - else: - for code in codes: - yield code - else: - while True: - try: - code = click.prompt("code", prompt_suffix=" >>> ") - code = code.strip() - if code == "exit": - break - if code: - yield code - except EOFError: - break - - for code in get_codes(): - name = context.GetMasterCodeName(code) - click.echo(name) diff --git a/koapy/cli/commands/install/__init__.py b/koapy/cli/commands/install/__init__.py deleted file mode 100644 index c46a5856..00000000 --- a/koapy/cli/commands/install/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import click - -from .openapi import openapi -from .pywin32 import pywin32 - - -@click.group(short_help="Install openapi module and others.") -def install(): - pass - - -install.add_command(openapi) -install.add_command(pywin32) diff --git a/koapy/cli/commands/install/openapi.py b/koapy/cli/commands/install/openapi.py deleted file mode 100644 index 663c82cb..00000000 --- a/koapy/cli/commands/install/openapi.py +++ /dev/null @@ -1,64 +0,0 @@ -import contextlib -import os -import shutil -import subprocess -import tempfile - -import click - -from koapy.cli.utils.openapi import ( - download_openapi_installer, - prepare_issfile_for_install, - run_installer_with_issfile, -) -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Install openapi module.") -@click.option( - "-t", - "--target", - metavar="TARGET", - type=click.Path(), - default="C:\\", - help='Target directory for installation. Will create "OpenAPI" folder under this directory for install. (default: "C:\\")', -) -@click.option( - "--cleanup/--no-cleanup", - default=True, - help="Clean up temporary directory after install. (default: true)", -) -@verbose_option(default=5, show_default=True) -def openapi(target, cleanup): - with contextlib.ExitStack() as stack: - tempdir = tempfile.mkdtemp() - logger.info("Created temporary directory: %s", tempdir) - if cleanup: - stack.callback(shutil.rmtree, tempdir) - logger.info("Registered to remove the temporary directory after install.") - installer_filename = "OpenAPISetup.exe" - installer_filepath = os.path.join(tempdir, installer_filename) - logger.info("Downloading installer: %s", installer_filepath) - download_openapi_installer(installer_filepath) - iss_filename = "setup.iss" - iss_filepath = os.path.join(tempdir, iss_filename) - logger.info("Preparing .iss file: %s", iss_filepath) - prepare_issfile_for_install(iss_filepath, target) - log_filename = "setup.log" - log_filepath = os.path.join(tempdir, log_filename) - try: - _return_code = run_installer_with_issfile( - installer_filepath, iss_filepath, log_filepath, cwd=tempdir - ) - except subprocess.CalledProcessError as e: - logger.exception( - "Failed to install openapi with return code: %d", e.returncode - ) - raise RuntimeError( - "Failed to install openapi with return code: %d" % e.returncode - ) from e - else: - logger.info("Succesfully installed openapi.") diff --git a/koapy/cli/commands/install/pywin32.py b/koapy/cli/commands/install/pywin32.py deleted file mode 100644 index 7d9fc5cd..00000000 --- a/koapy/cli/commands/install/pywin32.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from koapy.cli.utils.pywin32 import install_pywin32 -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Install pywin32 and run post install script.") -@click.option("--version", metavar="VERSION", help="Version of pywin32 to install.") -@verbose_option(default=5, show_default=True) -def pywin32(version): - install_pywin32(version) diff --git a/koapy/cli/commands/serve/__init__.py b/koapy/cli/commands/serve/__init__.py deleted file mode 100644 index 7db19a65..00000000 --- a/koapy/cli/commands/serve/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys - -import click - -from koapy.cli.utils.grpc_options import grpc_server_and_client_options -from koapy.cli.utils.verbose_option import full_verbose_option - - -@click.command( - context_settings=dict( - ignore_unknown_options=True, - ), - short_help="Start grpc server with tray application.", -) -@click.pass_context -@grpc_server_and_client_options() -@full_verbose_option() -@click.argument("args", nargs=-1, type=click.UNPROCESSED) -def serve( - ctx, - verbose, - **kwargs, -): - # reconstruct args so that only the first argument is program - # and others are real arguments - context_depth = 0 - c = ctx - while c is not None: - context_depth += 1 - c = c.parent - args = sys.argv[:1] + sys.argv[context_depth:] - - # force verbosity of created applications to follow the cli option - args.append("--verbose={}".format(verbose)) - - # call main function of manager application with the prepared args - from koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication import ( - KiwoomOpenApiPlusManagerApplication, - ) - - KiwoomOpenApiPlusManagerApplication.main(args) diff --git a/koapy/cli/commands/show/__init__.py b/koapy/cli/commands/show/__init__.py deleted file mode 100644 index eb215350..00000000 --- a/koapy/cli/commands/show/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import click - -from .account_window import account_window - - -@click.group(short_help="Show some configuration windows.") -def show(): - pass - - -show.add_command(account_window) diff --git a/koapy/cli/commands/show/account_window.py b/koapy/cli/commands/show/account_window.py deleted file mode 100644 index 92cb988c..00000000 --- a/koapy/cli/commands/show/account_window.py +++ /dev/null @@ -1,18 +0,0 @@ -import click - -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Show configuration window for auto login.") -@click.option( - "-p", "--port", metavar="PORT", help="Port number of grpc server (optional)." -) -@verbose_option() -def account_window(port): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint import ( - KiwoomOpenApiPlusEntrypoint, - ) - - with KiwoomOpenApiPlusEntrypoint(port=port) as context: - context.EnsureConnected() - context.ShowAccountWindow() diff --git a/koapy/cli/commands/uninstall/__init__.py b/koapy/cli/commands/uninstall/__init__.py deleted file mode 100644 index ea66d905..00000000 --- a/koapy/cli/commands/uninstall/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import click - -from .openapi import openapi -from .pywin32 import pywin32 - - -@click.group(short_help="Uninstall openapi module and others.") -def uninstall(): - pass - - -uninstall.add_command(openapi) -uninstall.add_command(pywin32) diff --git a/koapy/cli/commands/uninstall/openapi.py b/koapy/cli/commands/uninstall/openapi.py deleted file mode 100644 index ad0f25b6..00000000 --- a/koapy/cli/commands/uninstall/openapi.py +++ /dev/null @@ -1,61 +0,0 @@ -import contextlib -import os -import shutil -import subprocess -import tempfile - -import click - -from koapy.cli.utils.openapi import ( - download_openapi_installer, - prepare_issfile_for_uninstall, - run_installer_with_issfile, -) -from koapy.cli.utils.verbose_option import verbose_option -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -@click.command(short_help="Uninstall openapi module.") -@click.option( - "--reboot/--no-reboot", - default=False, - help="Reboot after uninstall. (default: false)", -) -@click.option( - "--cleanup/--no-cleanup", - default=True, - help="Clean up temporary directory after uninstall. (default: true)", -) -@verbose_option(default=5, show_default=True) -def openapi(reboot, cleanup): - with contextlib.ExitStack() as stack: - tempdir = tempfile.mkdtemp() - logger.info("Created temporary directory: %s", tempdir) - if cleanup: - stack.callback(shutil.rmtree, tempdir) - logger.info("Registered to remove the temporary directory after uninstall.") - installer_filename = "OpenAPISetup.exe" - installer_filepath = os.path.join(tempdir, installer_filename) - logger.info("Downloading installer: %s", installer_filepath) - download_openapi_installer(installer_filepath) - iss_filename = "setup.iss" - iss_filepath = os.path.join(tempdir, iss_filename) - logger.info("Preparing .iss file: %s", iss_filepath) - prepare_issfile_for_uninstall(iss_filepath, reboot) - log_filename = "setup.log" - log_filepath = os.path.join(tempdir, log_filename) - try: - _return_code = run_installer_with_issfile( - installer_filepath, iss_filepath, log_filepath, cwd=tempdir - ) - except subprocess.CalledProcessError as e: - logger.exception( - "Failed to uninstall openapi with return code: %d", e.returncode - ) - raise RuntimeError( - "Failed to uninstall openapi with return code: %d" % e.returncode - ) from e - else: - logger.info("Succesfully uninstalled openapi.") diff --git a/koapy/cli/commands/uninstall/pywin32.py b/koapy/cli/commands/uninstall/pywin32.py deleted file mode 100644 index ffb658f1..00000000 --- a/koapy/cli/commands/uninstall/pywin32.py +++ /dev/null @@ -1,10 +0,0 @@ -import click - -from koapy.cli.utils.pywin32 import uninstall_pywin32 -from koapy.cli.utils.verbose_option import verbose_option - - -@click.command(short_help="Uninstall pywin32 and run post uninstall script.") -@verbose_option(default=5, show_default=True) -def pywin32(): - uninstall_pywin32() diff --git a/koapy/cli/commands/update/__init__.py b/koapy/cli/commands/update/__init__.py deleted file mode 100644 index b5cc3245..00000000 --- a/koapy/cli/commands/update/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -import click - -from koapy.cli.utils.credentials import get_credentials -from koapy.cli.utils.verbose_option import verbose_option - - -@click.group(short_help="Update openapi module and metadata.") -def update(): - pass - - -@update.command(short_help="Update openapi TR metadata.") -@verbose_option() -def trinfo(): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo import ( - KiwoomOpenApiPlusTrInfo, - ) - - KiwoomOpenApiPlusTrInfo.dump_trinfo_by_code() - - -@update.command(short_help="Update openapi realtype metadata.") -@verbose_option() -def realtype(): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType import ( - KiwoomOpenApiPlusRealType, - ) - - KiwoomOpenApiPlusRealType.dump_realtype_by_desc() - - -@update.command(short_help="Update openapi module version.") -@click.option( - "-i", "--interactive", is_flag=True, help="Put login information with prompts." -) -@verbose_option(default=5, show_default=True) -def openapi(interactive): - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater import ( - KiwoomOpenApiPlusVersionUpdater, - ) - - credentials = get_credentials(interactive) - updater = KiwoomOpenApiPlusVersionUpdater(credentials) - updater.update_version_if_necessary() - - -@update.command(short_help="Update gRPC stub files by compiling proto files.") -def proto(): - from koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto import ( - compile_proto, - ) - - compile_proto() diff --git a/koapy/cli/extensions/__init__.py b/koapy/cli/extensions/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/extensions/functools.py b/koapy/cli/extensions/functools.py deleted file mode 100644 index 1fff614a..00000000 --- a/koapy/cli/extensions/functools.py +++ /dev/null @@ -1,11 +0,0 @@ -from functools import update_wrapper - - -def update_wrapper_with_click_params(wrapper, wrapped, *args, **kwargs): - click_params_wrapper = getattr(wrapper, "__click_params__", []) - click_params_wrapped = getattr(wrapped, "__click_params__", []) - click_params = click_params_wrapped + click_params_wrapper - wrapper.__click_params__ = click_params - wrapped.__click_params__ = click_params - updated_wrapper = update_wrapper(wrapper, wrapped, *args, **kwargs) - return updated_wrapper diff --git a/koapy/cli/extensions/parser.py b/koapy/cli/extensions/parser.py deleted file mode 100644 index f0027603..00000000 --- a/koapy/cli/extensions/parser.py +++ /dev/null @@ -1,140 +0,0 @@ -import sys - -from argparse import Namespace -from typing import Any, Callable, List, Optional, Sequence, Tuple, TypeVar, Union - -import click - -from click import Command - -Function = TypeVar("Function", bound=Callable[..., Any]) -FunctionOrCommand = TypeVar( - "FunctionOrCommand", bound=Union[Callable[..., Any], Command] -) - -ArgumentDecorator = Callable[[FunctionOrCommand], FunctionOrCommand] -CommandDecorator = Callable[[Function], Command] - - -class ArgumentParser: - def parse_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Namespace: - raise NotImplementedError - - def parse_known_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Tuple[Namespace, List[str]]: - raise NotImplementedError - - -class ClickArgumentParser(ArgumentParser): - - _unrecognized_args_attr = "args" - - def __init__( - self, - params: Sequence[ArgumentDecorator], - command: Optional[CommandDecorator] = None, - help_option_names: Optional[Sequence[str]] = None, - ): - if help_option_names is None: - help_option_names = ["-h", "--help"] - - if command is None: - command = click.command( - context_settings=dict(help_option_names=help_option_names) - ) - - self._params = params - self._command = command - self._help_option_names = help_option_names - - def _callback(self, *args, **kwargs): - return args, kwargs - - def _parse_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ignore_unknown_options: bool = False, - allow_extra_args: bool = False, - allow_interspersed_args: bool = True, - ) -> Tuple[Namespace, List[str]]: - - if args is None: - args = sys.argv[1:] - else: - args = list(args) - - if namespace is None: - namespace = Namespace() - - def callback(*args, **kwargs): - return self._callback(*args, **kwargs) - - if ignore_unknown_options: - unrecognized_args_param = click.argument( - self._unrecognized_args_attr, - nargs=-1, - type=click.UNPROCESSED, - metavar="[ARGS]...", - ) - callback = unrecognized_args_param(callback) - - for decorator in reversed(self._params): - callback = decorator(callback) - - command = self._command(callback) - context_settings = dict( - help_option_names=self._help_option_names, - ignore_unknown_options=ignore_unknown_options, - allow_extra_args=allow_extra_args, - allow_interspersed_args=allow_interspersed_args, - ) - command.context_settings.update(context_settings) - - ret = command.main(args, standalone_mode=False) - - if isinstance(ret, int): - sys.exit(ret) - - callback_args, callback_kwargs = ret - - assert len(callback_args) == 0 - - for key, value in callback_kwargs.items(): - setattr(namespace, key, value) - - unrecognized_args = [] - - if hasattr(namespace, self._unrecognized_args_attr): - unrecognized_args = getattr(namespace, self._unrecognized_args_attr) - unrecognized_args = list(unrecognized_args) - delattr(namespace, self._unrecognized_args_attr) - - return namespace, unrecognized_args - - def parse_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Namespace: - namespace, _unrecognized_args = self._parse_args(args, namespace) - return namespace - - def parse_known_args( - self, - args: Optional[Sequence[str]] = None, - namespace: Optional[Namespace] = None, - ) -> Tuple[Namespace, List[str]]: - namespace, unrecognized_args = self._parse_args( - args, - namespace, - ignore_unknown_options=True, - ) - return namespace, unrecognized_args diff --git a/koapy/cli/extensions/verbose_option.py b/koapy/cli/extensions/verbose_option.py deleted file mode 100644 index f4a232e8..00000000 --- a/koapy/cli/extensions/verbose_option.py +++ /dev/null @@ -1,132 +0,0 @@ -import click - -from click.parser import normalize_opt - -from koapy.cli.extensions.functools import update_wrapper_with_click_params - - -class VerboseOption(click.Option): - def __init__(self, *decls, **attrs): - self._flag_value = attrs.pop("flag_value", None) - super().__init__(*decls, **attrs) - self._parser = None - self._parser__match_long_opt = None - self._parser__match_short_opt = None - self._parser__get_value_from_state = None - - def _match_long_opt(self, opt, explicit_value, state): - # pylint: disable=protected-access - if opt in self.opts and opt in self._parser._long_opt: - option = self._parser._long_opt[opt] - option.action = "store" - self._parser__match_long_opt(opt, explicit_value, state) - - def _match_short_opt(self, arg, state): - # pylint: disable=protected-access - prefix = arg[0] - for ch in arg[1:]: - opt = normalize_opt(f"{prefix}{ch}", self._parser.ctx) - if opt in self.opts and opt in self._parser._short_opt: - option = self._parser._short_opt[opt] - option.action = "count" - self._parser__match_short_opt(arg, state) - - def _get_value_from_state(self, option_name, option, state): - # pylint: disable=protected-access - try: - value = self._parser__get_value_from_state(option_name, option, state) - except click.BadOptionUsage: - value = self._flag_value - else: - if option_name in self.opts: - if ( - isinstance(value, str) - and value[:1] in self._parser._opt_prefixes - and len(value) > 1 - ): - state.rargs.insert(0, value) - value = self._flag_value - return value - - def _patch_parser(self, parser): - # pylint: disable=protected-access - self._parser = parser - self._parser__match_short_opt = self._parser._match_short_opt - self._parser._match_short_opt = self._match_short_opt - self._parser__match_long_opt = self._parser._match_long_opt - self._parser._match_long_opt = self._match_long_opt - self._parser__get_value_from_state = self._parser._get_value_from_state - self._parser._get_value_from_state = self._get_value_from_state - - def add_to_parser(self, parser, ctx): - self._patch_parser(parser) - super().add_to_parser(parser, ctx) - - -def verbose_flag_option( - default=0, - flag_value=1, - show_default=False, - metavar="[0...5]", - help="Set verbosity level.", -): - # pylint: disable=redefined-builtin - return click.option( - "-v", - "--verbose", - type=int, - default=default, - flag_value=flag_value, - show_default=show_default, - metavar=metavar, - help=help, - cls=VerboseOption, - ) - - -def no_verbose_flag_option( - help="Force zero verbosity.", -): - # pylint: disable=redefined-builtin - return click.option( - "-s", - "--no-verbose", - "--slient", - is_flag=True, - default=False, - help=help, - ) - - -def verbose_option( - dest="verbose", - default=0, - flag_value=1, - callback=None, - expose_value=False, - show_default=False, -): - def decorator(f): - @click.pass_context - @verbose_flag_option( - default=default, - flag_value=flag_value, - show_default=show_default, - ) - @no_verbose_flag_option() - def new_func(ctx, *args, **kwargs): - verbose = kwargs.pop("verbose") - no_verbose = kwargs.pop("no_verbose") - if no_verbose: - verbose = 0 - if expose_value: - kwargs[dest] = verbose - if callable(callback): - param = ctx.params.get("verbose") - value = verbose - callback(ctx, param, value) - return ctx.invoke(f, *args, **kwargs) - - return update_wrapper_with_click_params(new_func, f) - - return decorator diff --git a/koapy/cli/utils/__init__.py b/koapy/cli/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/cli/utils/credentials.py b/koapy/cli/utils/credentials.py deleted file mode 100644 index ae9db7ee..00000000 --- a/koapy/cli/utils/credentials.py +++ /dev/null @@ -1,109 +0,0 @@ -import os - -import click - -from koapy.config import ( - config, - config_from_dict, - default_user_config_filepath, - save_config, - user_config, -) - - -def prompt_credentials(): - credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") - - default_user_id = credentials["user_id"] - default_user_password = credentials["user_password"] - default_server = "simulation" if credentials["is_simulation"] else "real" - default_cert_password = credentials["cert_password"] - - user_id = click.prompt("User ID", default=default_user_id) - user_password = click.prompt( - "User Password", - hide_input=True, - default=default_user_password, - show_default=False, - ) - is_simulation = ( - click.prompt( - "Server Type", - type=click.Choice(["real", "simulation"], case_sensitive=False), - default=default_server, - ) - == "simulation" - ) - if is_simulation: - cert_password = default_cert_password - else: - cert_password = click.prompt( - "Cert Password", - hide_input=True, - default=default_cert_password, - show_default=False, - ) - - account_passwords = {} - if is_simulation: - account_passwords["0000000000"] = "0000" - else: - account_count = click.prompt("Account Count", type=int, default=1) - for _ in range(account_count): - account_number = click.prompt("Account Number", default="0000000000") - account_password = click.prompt( - "Account Password", - hide_input=True, - show_default=False, - ) - account_passwords[account_number] = account_password - - credentials = { - "user_id": user_id, - "user_password": user_password, - "cert_password": cert_password, - "is_simulation": is_simulation, - "account_passwords": account_passwords, - } - credentials = config_from_dict(credentials) - - return credentials - - -def get_credentials(interactive=False): - if not interactive: - credentials = config.get("koapy.backend.kiwoom_open_api_plus.credentials") - else: - credentials = prompt_credentials() - save_credentials = ( - click.prompt( - "Save credentials info into a config file?", - type=click.Choice(["y", "n"], case_sensitive=False), - default="n", - ) - == "y" - ) - if save_credentials: - config_path = click.prompt( - "Path to save config file", default=default_user_config_filepath - ) - - if os.path.exists(config_path): - should_write = ( - click.prompt( - "The file already exists, overwrite?", - type=click.Choice(["y", "n"], case_sensitive=False), - default="n", - ) - == "y" - ) - else: - should_write = True - - if should_write: - user_config.put( - "koapy.backend.kiwoom_open_api_plus.credentials", credentials - ) - save_config(config_path, user_config) - - return credentials diff --git a/koapy/cli/utils/cybos_plus.py b/koapy/cli/utils/cybos_plus.py deleted file mode 100644 index 635e1e87..00000000 --- a/koapy/cli/utils/cybos_plus.py +++ /dev/null @@ -1,8 +0,0 @@ -import requests - - -def download_cybos_plus_installer(filepath): - url = "https://www.daishin.com/install/CYBOS5.exe" - response = requests.get(url) - with open(filepath, "wb") as f: - f.write(response.content) diff --git a/koapy/cli/utils/fail_with_usage.py b/koapy/cli/utils/fail_with_usage.py deleted file mode 100644 index 87bb3c57..00000000 --- a/koapy/cli/utils/fail_with_usage.py +++ /dev/null @@ -1,27 +0,0 @@ -import click - - -def get_help(ctx): - return ctx.get_help() - - -def get_help_without_usage(ctx): - formatter = ctx.make_formatter() - command = ctx.command - command.format_help_text(ctx, formatter) - command.format_options(ctx, formatter) - command.format_epilog(ctx, formatter) - help_without_usage = formatter.getvalue().rstrip("\n") - return help_without_usage - - -def fail_with_usage(message=None, ctx=None): - if ctx is None: - ctx = click.get_current_context() - if message is not None: - click.UsageError(message, ctx).show() - click.echo() - click.echo(get_help_without_usage(ctx)) - else: - click.echo(get_help(ctx)) - ctx.exit(click.UsageError.exit_code) diff --git a/koapy/cli/utils/grpc_options.py b/koapy/cli/utils/grpc_options.py deleted file mode 100644 index d27bf89e..00000000 --- a/koapy/cli/utils/grpc_options.py +++ /dev/null @@ -1,384 +0,0 @@ -import click - -from koapy.cli.extensions.functools import update_wrapper_with_click_params -from koapy.cli.extensions.parser import ClickArgumentParser -from koapy.cli.utils.verbose_option import full_verbose_option -from koapy.config import config - -# grpc configs for default values -grpc_config = config.get("koapy.backend.kiwoom_open_api_plus.grpc") - -default_server_bind_address = ( - grpc_config.get("server.bind_address") - or grpc_config.get("server.host") - or grpc_config.get("host") -) -default_server_host = default_server_bind_address -default_server_port = grpc_config.get("server.port") or grpc_config.get("port") - -default_client_host = grpc_config.get("client.host") or grpc_config.get("host") -default_client_port = grpc_config.get("client.port") or grpc_config.get("port") - -default_common_host = grpc_config.get("host") or grpc_config.get("client.host") -default_common_port = ( - grpc_config.get("port") - or grpc_config.get("server.port") - or grpc_config.get("client.port") -) - - -# server specific options -server_bind_address_option = click.option( - "--bind-address", - "--host", - metavar="ADDRESS", - help="Host address of gRPC server to bind.", - default=default_server_bind_address, - show_default=True, -) -server_port_option = click.option( - "--port", - metavar="PORT", - type=int, - help="Port number of gRPC server to bind.", - default=default_server_port, - show_default=True, -) -server_key_file_option = click.option( - "--key-file", - type=click.Path(), - help="PEM encoded private key file for server SSL/TLS.", -) -server_cert_file_option = click.option( - "--cert-file", - type=click.Path(), - help="PEM encoded certificate chain file for server SSL/TLS.", -) -server_root_certs_file_option = click.option( - "--root-certs-file", - type=click.Path(), - help=""" - PEM encoded client root certificates file for client authentication. - Assumes --require-client-auth flag is set if this option is given, - unless --no-require-client-auth flag is set explicitly. - """, -) -server_require_client_auth_option = click.option( - "--require-client-auth", - help="Require clients to be authenticated, root certificates are required.", - is_flag=True, -) -server_no_require_client_auth_option = click.option( - "--no-require-client-auth", - help="Force not to require clients to be authenticated, even if root certificates are given.", - is_flag=True, -) - -server_options = [ - server_bind_address_option, - server_port_option, - server_key_file_option, - server_cert_file_option, - server_root_certs_file_option, - server_require_client_auth_option, - server_no_require_client_auth_option, -] - - -# client specific options -client_host_option = click.option( - "--host", - metavar="ADDRESS", - help="Host address of gRPC server to connect.", - default=default_client_host, - show_default=True, -) -client_port_option = click.option( - "--port", - metavar="PORT", - type=int, - help="Port number of gRPC server to connect.", - default=default_client_port, - show_default=True, -) -client_enable_ssl_option = click.option( - "--enable-ssl", - help=""" - Enable SSL/TLS for gRPC connection. - If --root-certs-file option is not given, - will retrieve them from a default location chosen by gRPC runtime. - """, - is_flag=True, -) -client_root_certs_file_option = click.option( - "--root-certs-file", - type=click.Path(), - help="PEM encoded root certificates file for SSL/TLS.", -) -client_key_file_option = click.option( - "--key-file", - type=click.Path(), - help="PEM encoded private key file for client authentication.", -) -client_cert_file_option = click.option( - "--cert-file", - type=click.Path(), - help="PEM encoded certificate chain file for client authentication.", -) - -client_options = [ - client_host_option, - client_port_option, - client_enable_ssl_option, - client_root_certs_file_option, - client_key_file_option, - client_cert_file_option, -] - - -# server and client options (resolving option conflicts) -server_and_client_bind_address_option = click.option( - "--bind-address", - "--server-host", - metavar="ADDRESS", - help="Host address of gRPC server to bind.", - default=default_server_bind_address, - show_default=True, -) -server_and_client_host_option = click.option( - "--host", - "--client-host", - metavar="ADDRESS", - help="Host address of gRPC server to connect.", - default=default_client_host, - show_default=True, -) -server_and_client_port_option = click.option( - "--port", - metavar="PORT", - type=int, - help="Port number of gRPC server to bind and connect.", - default=default_common_port, - show_default=True, -) -server_and_client_enable_ssl_option = click.option( - "--enable-ssl", - help=""" - Enable SSL/TLS for gRPC connection. - If --client-root-certs-file option is not given, - will retrieve them from a default location chosen by gRPC runtime. - """, - is_flag=True, - show_default=True, -) -server_and_client_server_key_file_option = click.option( - "--server-key-file", - type=click.Path(), - help="PEM encoded private key file for server SSL/TLS.", -) -server_and_client_server_cert_file_option = click.option( - "--server-cert-file", - type=click.Path(), - help="PEM encoded certificate chain file for server SSL/TLS.", -) -server_and_client_server_root_certs_file_option = click.option( - "--server-root-certs-file", - type=click.Path(), - help=""" - PEM encoded client root certificates file for client authentication. - Assumes --require-client-auth flag is set if this option is given, - unless --no-require-client-auth flag is set explicitly. - """, -) -server_and_client_require_client_auth_option = click.option( - "--require-client-auth", - help="Require clients to be authenticated, root certificates are required.", - is_flag=True, -) -server_and_client_no_require_client_auth_option = click.option( - "--no-require-client-auth", - help="Foce not to require clients to be authenticated, even if root certificates are given.", - is_flag=True, -) -server_and_client_client_root_certs_file_option = click.option( - "--client-root-certs-file", - type=click.Path(), - help="PEM encoded root certificates file for SSL/TLS.", -) -server_and_client_client_key_file_option = click.option( - "--client-key-file", - type=click.Path(), - help="PEM encoded private key file for client authentication.", -) -server_and_client_client_cert_file_option = click.option( - "--client-cert-file", - type=click.Path(), - help="PEM encoded certificate chain file for client authentication.", -) - -server_and_client_options = [ - server_and_client_bind_address_option, - server_and_client_host_option, - server_and_client_port_option, - server_and_client_enable_ssl_option, - server_and_client_server_key_file_option, - server_and_client_server_cert_file_option, - server_and_client_server_root_certs_file_option, - server_and_client_require_client_auth_option, - server_and_client_no_require_client_auth_option, - server_and_client_client_root_certs_file_option, - server_and_client_client_key_file_option, - server_and_client_client_cert_file_option, -] - - -def grpc_server_options(): - def decorator(f): - @click.pass_context - @server_bind_address_option - @server_port_option - @server_key_file_option - @server_cert_file_option - @server_root_certs_file_option - @server_require_client_auth_option - @server_no_require_client_auth_option - def new_func(ctx: click.Context, *args, **kwargs): - key_file = kwargs.get("key_file") - cert_file = kwargs.get("cert_file") - root_certs_file = kwargs.get("root_certs_file") - require_client_auth = kwargs.get("require_client_auth") - no_require_client_auth = kwargs.pop("no_require_client_auth") - - # both --key-file and --cert-file should be given - if bool(key_file) != bool(cert_file): - ctx.fail("both --key-file and --cert-file should be given.") - - # assume --require-client-auth flag is set if --root-certs-file is given - if root_certs_file is not None: - require_client_auth = True - kwargs["require_client_auth"] = require_client_auth - - # value of --require-client-auth flag should be false if --no-require-client-auth flag is set - if no_require_client_auth: - require_client_auth = False - kwargs["require_client_auth"] = require_client_auth - - # --require-client-auth flag is set but no --root-certs-file was given - if require_client_auth and root_certs_file is None: - ctx.fail( - "--require-client-auth flag is set but no --root-certs-file was given." - ) - - return ctx.invoke(f, *args, **kwargs) - - return update_wrapper_with_click_params(new_func, f) - - return decorator - - -def grpc_client_options(): - def decorator(f): - @click.pass_context - @client_host_option - @client_port_option - @client_enable_ssl_option - @client_root_certs_file_option - @client_key_file_option - @client_cert_file_option - def new_func(ctx: click.Context, *args, **kwargs): - enable_ssl = kwargs.get("enable_ssl") - root_certs_file = kwargs.get("root_certs_file") - key_file = kwargs.get("key_file") - cert_file = kwargs.get("cert_file") - - # assume --enable-ssl flag is set if --root-certs-file is given - if root_certs_file is not None: - enable_ssl = True - kwargs["enable_ssl"] = enable_ssl - - # both --key-file and --cert-file should be given - if bool(key_file) != bool(cert_file): - ctx.fail("both --key-file and --cert-file should be given.") - - return ctx.invoke(f, *args, **kwargs) - - return update_wrapper_with_click_params(new_func, f) - - return decorator - - -def grpc_server_and_client_options(): - def decorator(f): - @click.pass_context - @server_and_client_bind_address_option - @server_and_client_host_option - @server_and_client_port_option - @server_and_client_enable_ssl_option - @server_and_client_server_key_file_option - @server_and_client_server_cert_file_option - @server_and_client_server_root_certs_file_option - @server_and_client_require_client_auth_option - @server_and_client_no_require_client_auth_option - @server_and_client_client_root_certs_file_option - @server_and_client_client_key_file_option - @server_and_client_client_cert_file_option - def new_func(ctx: click.Context, *args, **kwargs): - # server related options and logics - key_file = kwargs.get("server_key_file") - cert_file = kwargs.get("server_cert_file") - root_certs_file = kwargs.get("server_root_certs_file") - require_client_auth = kwargs.get("require_client_auth") - no_require_client_auth = kwargs.pop("no_require_client_auth") - - # both --key-file and --cert-file should be given - if bool(key_file) != bool(cert_file): - ctx.fail( - "both --server-key-file and --server-cert-file should be given." - ) - - # assume --require-client-auth flag is set if --root-certs-file is given - if root_certs_file is not None: - require_client_auth = True - kwargs["require_client_auth"] = require_client_auth - - # value of --require-client-auth flag should be false if --no-require-client-auth flag is set - if no_require_client_auth: - require_client_auth = False - kwargs["require_client_auth"] = require_client_auth - - # --require-client-auth flag is set but no --root-certs-file was given - if require_client_auth and root_certs_file is None: - ctx.fail( - "--require-client-auth flag is set but no --server-root-certs-file was given." - ) - - # client related options and logics - enable_ssl = kwargs.get("enable_ssl") - root_certs_file = kwargs.get("client_root_certs_file") - key_file = kwargs.get("client_key_file") - cert_file = kwargs.get("client_cert_file") - - # assume --enable-ssl flag is set if --root-certs-file is given - if root_certs_file is not None: - enable_ssl = True - kwargs["enable_ssl"] = enable_ssl - - # both --key-file and --cert-file should be given - if bool(key_file) != bool(cert_file): - ctx.fail( - "both --client-key-file and --client-cert-file should be given." - ) - - return ctx.invoke(f, *args, **kwargs) - - return update_wrapper_with_click_params(new_func, f) - - return decorator - - -server_argument_parser = ClickArgumentParser(server_options + [full_verbose_option()]) -client_argument_parser = ClickArgumentParser(client_options + [full_verbose_option()]) - -server_and_client_argument_parser = ClickArgumentParser( - server_and_client_options + [full_verbose_option()] -) diff --git a/koapy/cli/utils/openapi.py b/koapy/cli/utils/openapi.py deleted file mode 100644 index d001ed48..00000000 --- a/koapy/cli/utils/openapi.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -import shutil -import subprocess - -import requests - -from koapy.utils.logging import get_logger -from koapy.utils.subprocess import quote - -logger = get_logger(__name__) - -iss_file_encoding = "euc-kr" - - -def download_openapi_installer(filepath): - url = "https://download.kiwoom.com/web/openapi/OpenAPISetup.exe" - response = requests.get(url) - with open(filepath, "wb") as f: - f.write(response.content) - - -def prepare_issfile_for_install(filepath, target=None): - iss_filedir = os.path.join( - os.path.dirname(__file__), - "../../backend/kiwoom_open_api_plus/data/scripts/", - ) - iss_filename = "install.iss" - iss_filepath = os.path.join(iss_filedir, iss_filename) - shutil.copy(iss_filepath, filepath) - if target is not None: - with open(filepath, "r", encoding=iss_file_encoding) as f: - lines = [line for line in f] - for i, line in enumerate(lines): - if line.startswith("szDir="): - lines[i] = "szDir={}\n".format(target) - break - with open(filepath, "w", encoding=iss_file_encoding) as f: - for line in lines: - f.write(line) - - -def prepare_issfile_for_uninstall(filepath, reboot=False): - iss_filedir = os.path.join( - os.path.dirname(__file__), - "../../backend/kiwoom_open_api_plus/data/scripts/", - ) - iss_filename = "uninstall.iss" - iss_filepath = os.path.join(iss_filedir, iss_filename) - shutil.copy(iss_filepath, filepath) - if reboot: - with open(filepath, "r", encoding=iss_file_encoding) as f: - lines = [line for line in f] - for i, line in enumerate(lines): - if line.startswith("BootOption="): - boot_option = 3 - lines[i] = "BootOption={}\n".format(boot_option) - break - with open(filepath, "w", encoding=iss_file_encoding) as f: - for line in lines: - f.write(line) - - -def run_installer_with_issfile(installer, issfile, logfile=None, cwd=None): - cmd = [quote(installer), "/s", "/f1{}".format(quote(issfile))] - if logfile is not None: - cmd.extend(["/f2{}".format(quote(logfile))]) - # should use shell=True in order not to escape quotes in args - logger.info("Running command: %s", " ".join(cmd)) - proc = subprocess.run(" ".join(cmd), shell=True, check=False, cwd=cwd) - if proc.returncode < 0: - raise subprocess.CalledProcessError(proc.returncode, " ".join(cmd)) - return proc.returncode diff --git a/koapy/cli/utils/pywin32.py b/koapy/cli/utils/pywin32.py deleted file mode 100644 index 29d3cad8..00000000 --- a/koapy/cli/utils/pywin32.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import subprocess -import sys -import tempfile - -import requests - -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -def get_pywin32_postinstall_script(filepath): - url = ( - "https://raw.githubusercontent.com/mhammond/pywin32/main/pywin32_postinstall.py" - ) - response = requests.get(url) - with open(filepath, "wb") as f: - f.write(response.content) - - -def install_pywin32(version=None): - if version is None: - version = "304" - cmd = ["pip", "install", "pywin32>={}".format(version)] - logger.info("Running command: %s", subprocess.list2cmdline(cmd)) - subprocess.check_call(cmd) - with tempfile.TemporaryDirectory() as tempdir: - script_filename = "pywin32_postinstall.py" - script_filepath = os.path.join(tempdir, script_filename) - get_pywin32_postinstall_script(script_filepath) - cmd = [sys.executable, script_filepath, "-install"] - logger.info("Running command: %s", subprocess.list2cmdline(cmd)) - subprocess.check_call(cmd) - - -def uninstall_pywin32(): - with tempfile.TemporaryDirectory() as tempdir: - script_filename = "pywin32_postinstall.py" - script_filepath = os.path.join(tempdir, script_filename) - get_pywin32_postinstall_script(script_filepath) - cmd = [sys.executable, script_filepath, "-remove"] - logger.info("Running command: %s", subprocess.list2cmdline(cmd)) - subprocess.check_call(cmd) - cmd = ["pip", "uninstall", "pywin32"] - logger.info("Running command: %s", subprocess.list2cmdline(cmd)) - subprocess.check_call(cmd) diff --git a/koapy/cli/utils/verbose_option.py b/koapy/cli/utils/verbose_option.py deleted file mode 100644 index 470c7eac..00000000 --- a/koapy/cli/utils/verbose_option.py +++ /dev/null @@ -1,27 +0,0 @@ -from koapy.cli.extensions.verbose_option import ( - verbose_option as extensions_verbose_option, -) -from koapy.utils.logging import set_verbosity - -full_verbosity = 5 - - -def verbose_option_callback(ctx, param, value): - set_verbosity(value) - - -def verbose_option(*args, **kwargs): - if "callback" not in kwargs: - kwargs["callback"] = verbose_option_callback - return extensions_verbose_option(*args, **kwargs) - - -def full_verbose_option(*args, **kwargs): - default_kwargs = dict( - default=full_verbosity, - show_default=True, - expose_value=True, - ) - kwargs = dict(kwargs) - kwargs.update(default_kwargs) - return verbose_option(*args, **kwargs) diff --git a/koapy/common/Dispatch.py b/koapy/common/Dispatch.py deleted file mode 100644 index e394056c..00000000 --- a/koapy/common/Dispatch.py +++ /dev/null @@ -1,117 +0,0 @@ -import types - -from threading import RLock -from typing import Union - -from pythoncom import ProgIDFromCLSID -from pythoncom import com_error as PythonComError -from pywintypes import IID -from win32com.client import getevents as GetEvents -from win32com.client.gencache import EnsureDispatch - -from koapy.common.EventInstance import EventInstance - - -class DispatchInstance: - def __init__(self, clsid: Union[IID, str]): - if isinstance(clsid, str): - clsid = IID(clsid) - - self._clsid = clsid - self._disp = EnsureDispatch(self._clsid) - self._events_class = GetEvents(self._clsid) - - if self._events_class: - - def exec_body(ns): - # pylint: disable=protected-access - for name in self._events_class._dispid_to_func_.values(): - ns[name] = EventInstance() - - self._user_event_class = types.new_class( - name="UserDispatchEventClass", - bases=(), - kwds={}, - exec_body=exec_body, - ) - self._result_class = types.new_class( - name="DispatchEventClass", - bases=(self._events_class, self._user_event_class), - kwds={}, - ) - - self._disp_events = self._result_class(self._disp) - - if hasattr(self._user_event_class, "__init__"): - # pylint: disable=non-parent-init-called - self._user_event_class.__init__(self._disp_events) - else: - self._disp_events = None - - def __del__(self): - if ( - "_disp_events" in self.__dict__ - and self.__dict__["_disp_events"] is not None - ): - try: - self.__dict__["_disp_events"].close() - except PythonComError: - pass - - def __getattr__(self, name): - if "_disp" in self.__dict__ and hasattr(self.__dict__["_disp"], name): - return getattr(self.__dict__["_disp"], name) - if "_disp_events" in self.__dict__ and hasattr( - self.__dict__["_disp_events"], name - ): - return getattr(self.__dict__["_disp_events"], name) - return super().__getattribute__(name) - - def __setattr__(self, name, value): - if name in self.__dict__: - return super().__setattr__(name, value) - if "_disp" in self.__dict__ and hasattr(self.__dict__["_disp"], name): - return setattr(self.__dict__["_disp"], name, value) - return super().__setattr__(name, value) - - def __dir__(self): - res = super().__dir__() - res = set(res) - if "_disp" in self.__dict__: - disp_dir = dir(self.__dict__["_disp"]) - res = res.union(set(disp_dir)) - if "_disp_events" in self.__dict__: - disp_events_dir = dir(self.__dict__["_disp_events"]) - res = res.union(set(disp_events_dir)) - res = list(res) - return res - - def __repr__(self): - class_name = self.__class__.__name__ - progid = ProgIDFromCLSID(self._clsid) - return f"{class_name}({progid!r})" - - -class DispatchMeta(type): - def __new__(cls, name, bases, namespace): - return super().__new__(cls, name, bases, namespace) - - def __init__(cls, name, bases, namespace): - super().__init__(name, bases, namespace) - - cls.INSTANCES = {} - cls.LOCK = RLock() - - def __call__(cls, clsid: Union[IID, str]): - if isinstance(clsid, str): - clsid = IID(clsid) - if clsid not in cls.INSTANCES: - with cls.LOCK: - if clsid not in cls.INSTANCES: - cls.INSTANCES[clsid] = super().__call__(clsid) - instance = cls.INSTANCES[clsid] - return instance - - -class Dispatch(DispatchInstance, metaclass=DispatchMeta): - pass diff --git a/koapy/common/DispatchProxyService.proto b/koapy/common/DispatchProxyService.proto deleted file mode 100644 index bf77da45..00000000 --- a/koapy/common/DispatchProxyService.proto +++ /dev/null @@ -1,87 +0,0 @@ -syntax = "proto3"; - -service DispatchProxyService { - rpc GetDispatch(GetDispatchRequest) returns (GetDispatchResponse) {}; - rpc GetAttr(GetAttrRequest) returns (GetAttrResponse) {}; - rpc SetAttr(SetAttrRequest) returns (SetAttrResponse) {}; - rpc CallMethod(CallMethodRequest) returns (CallMethodResponse) {}; - rpc ConnectEvent(stream ConnectEventRequest) returns (stream ConnectEventResponse) {}; -} - -message GetDispatchRequest { - string iid = 1; -} - -message GetDispatchResponse { - string iid = 1; -} - -message Value { - oneof value { - string string_value = 1; - int32 short_value = 2; - int32 int_value = 3; - int64 long_value = 4; - bool bool_value = 5; - double double_value = 6; - ValueArray list_value = 7; - ValueArray tuple_value = 8; - } -} - -message ValueArray { - repeated Value values = 1; -} - -message GetAttrRequest { - string iid = 1; - string name = 2; -} - -message GetAttrResponse { - Value value = 1; -} - -message SetAttrRequest { - string iid = 1; - string name = 2; - Value value = 3; -} - -message SetAttrResponse { -} - -message Argument { - Value value = 1; -} - -message CallMethodRequest { - string iid = 1; - string name = 2; - repeated Argument arguments = 3; -} - -message CallMethodResponse { - Value return_value = 1; -} - -message ConnectEventEstablishRequest { - string iid = 1; - string name = 2; -} - -message ConnectEventAckRequest { -} - -message ConnectEventRequest { - oneof request { - ConnectEventEstablishRequest establish_request = 1; - ConnectEventAckRequest ack_request = 2; - } -} - -message ConnectEventResponse { - string iid = 1; - string name = 2; - repeated Argument arguments = 3; -} diff --git a/koapy/common/DispatchProxyServiceMessageUtils.py b/koapy/common/DispatchProxyServiceMessageUtils.py deleted file mode 100644 index 02ddd78f..00000000 --- a/koapy/common/DispatchProxyServiceMessageUtils.py +++ /dev/null @@ -1,35 +0,0 @@ -def AssignValue(message, value): - if value is None: - pass - elif isinstance(value, str): - message.string_value = value - elif isinstance(value, int): - message.long_value = value - elif isinstance(value, bool): - message.bool_value = value - elif isinstance(value, float): - message.double_value = value - elif isinstance(value, list): - for item in value: - AssignValue(message.list_value.values.add(), item) - elif isinstance(value, tuple): - for item in value: - AssignValue(message.tuple_value.values.add(), item) - else: - raise TypeError - return message - - -def ExtractValue(message): - if message.HasField("string_value"): - return message.string_value - elif message.HasField("long_value"): - return message.long_value - elif message.HasField("bool_value"): - return message.bool_value - elif message.HasField("double_value"): - return message.double_value - elif message.HasField("list_value"): - return list(ExtractValue(value) for value in message.list_value.values) - elif message.HasField("tuple_value"): - return tuple(ExtractValue(value) for value in message.tuple_value.values) diff --git a/koapy/common/DispatchProxyServiceServicer.py b/koapy/common/DispatchProxyServiceServicer.py deleted file mode 100644 index 0488dc95..00000000 --- a/koapy/common/DispatchProxyServiceServicer.py +++ /dev/null @@ -1,117 +0,0 @@ -import atexit - -from queue import Queue -from typing import Iterator, Union - -from grpc import ServicerContext -from pywintypes import IID - -from koapy.common import DispatchProxyService_pb2, DispatchProxyService_pb2_grpc -from koapy.common.Dispatch import Dispatch -from koapy.common.DispatchProxyServiceMessageUtils import AssignValue, ExtractValue -from koapy.common.EventInstance import EventInstance - - -class DispatchProxyServiceServicer( - DispatchProxyService_pb2_grpc.DispatchProxyServiceServicer -): - def _GetDispatch(self, iid: Union[IID, str]) -> Dispatch: - return Dispatch(iid) - - def GetDispatch( - self, - request: DispatchProxyService_pb2.GetDispatchRequest, - context: ServicerContext, - ) -> DispatchProxyService_pb2.GetDispatchResponse: - iid = request.iid - iid = IID(iid) - iid = str(iid) - response = DispatchProxyService_pb2.GetDispatchResponse() - response.iid = iid - return response - - def GetAttr( - self, - request: DispatchProxyService_pb2.GetAttrRequest, - context: ServicerContext, - ) -> DispatchProxyService_pb2.GetAttrResponse: - iid = request.iid - name = request.name - dispatch = self._GetDispatch(iid) - value = getattr(dispatch, name) - response = DispatchProxyService_pb2.GetAttrResponse() - AssignValue(response.value, value) - return response - - def SetAttr( - self, - request: DispatchProxyService_pb2.SetAttrRequest, - context: ServicerContext, - ) -> DispatchProxyService_pb2.SetAttrResponse: - iid = request.iid - name = request.name - value = request.value - dispatch = self._GetDispatch(iid) - setattr(dispatch, name, value) - response = DispatchProxyService_pb2.SetAttrResponse() - return response - - def CallMethod( - self, - request: DispatchProxyService_pb2.CallMethodRequest, - context: ServicerContext, - ) -> DispatchProxyService_pb2.CallMethodResponse: - iid = request.iid - name = request.name - arguments = request.arguments - arguments = [ExtractValue(arg.value) for arg in arguments] - dispatch = self._GetDispatch(iid) - method = getattr(dispatch, name) - return_value = method(*arguments) - response = DispatchProxyService_pb2.CallMethodResponse() - AssignValue(response.return_value, return_value) - return response - - def ConnectEvent( - self, - request_iterator: Iterator[DispatchProxyService_pb2.ConnectEventRequest], - context: ServicerContext, - ) -> Iterator[DispatchProxyService_pb2.ConnectEventResponse]: - request = next(request_iterator) - assert request.HasField("establish_request") - - request = request.establish_request - iid = request.iid - iid = IID(iid) - iid = str(iid) - name = request.name - dispatch = self._GetDispatch(iid) - event_instance: EventInstance = getattr(dispatch, name) - queue = Queue() - sentinel = object() - - def slot(*args, **_kwargs): - queue.put(args) - request = next(request_iterator) - assert request.HasField("ack_request") - - def put_sentinel(): - queue.put(sentinel) - - def callback(): - event_instance.disconnect(slot) - atexit.unregister(put_sentinel) - queue.put(sentinel) - - context.add_callabck(callback) - atexit.register(put_sentinel) - event_instance.connect(slot) - - for args in iter(queue.get, sentinel): - response = DispatchProxyService_pb2.ConnectEventResponse() - response.iid = iid - response.name = name - for arg in args: - AssignValue(response.arguments.add().value, arg) - queue.task_done() - yield response diff --git a/koapy/common/DispatchProxyService_pb2.py b/koapy/common/DispatchProxyService_pb2.py deleted file mode 100644 index be4dcf16..00000000 --- a/koapy/common/DispatchProxyService_pb2.py +++ /dev/null @@ -1,54 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: koapy/common/DispatchProxyService.proto -"""Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\'koapy/common/DispatchProxyService.proto\"!\n\x12GetDispatchRequest\x12\x0b\n\x03iid\x18\x01 \x01(\t\"\"\n\x13GetDispatchResponse\x12\x0b\n\x03iid\x18\x01 \x01(\t\"\xdf\x01\n\x05Value\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x15\n\x0bshort_value\x18\x02 \x01(\x05H\x00\x12\x13\n\tint_value\x18\x03 \x01(\x05H\x00\x12\x14\n\nlong_value\x18\x04 \x01(\x03H\x00\x12\x14\n\nbool_value\x18\x05 \x01(\x08H\x00\x12\x16\n\x0c\x64ouble_value\x18\x06 \x01(\x01H\x00\x12!\n\nlist_value\x18\x07 \x01(\x0b\x32\x0b.ValueArrayH\x00\x12\"\n\x0btuple_value\x18\x08 \x01(\x0b\x32\x0b.ValueArrayH\x00\x42\x07\n\x05value\"$\n\nValueArray\x12\x16\n\x06values\x18\x01 \x03(\x0b\x32\x06.Value\"+\n\x0eGetAttrRequest\x12\x0b\n\x03iid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"(\n\x0fGetAttrResponse\x12\x15\n\x05value\x18\x01 \x01(\x0b\x32\x06.Value\"B\n\x0eSetAttrRequest\x12\x0b\n\x03iid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x15\n\x05value\x18\x03 \x01(\x0b\x32\x06.Value\"\x11\n\x0fSetAttrResponse\"!\n\x08\x41rgument\x12\x15\n\x05value\x18\x01 \x01(\x0b\x32\x06.Value\"L\n\x11\x43\x61llMethodRequest\x12\x0b\n\x03iid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1c\n\targuments\x18\x03 \x03(\x0b\x32\t.Argument\"2\n\x12\x43\x61llMethodResponse\x12\x1c\n\x0creturn_value\x18\x01 \x01(\x0b\x32\x06.Value\"9\n\x1c\x43onnectEventEstablishRequest\x12\x0b\n\x03iid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x18\n\x16\x43onnectEventAckRequest\"\x8c\x01\n\x13\x43onnectEventRequest\x12:\n\x11\x65stablish_request\x18\x01 \x01(\x0b\x32\x1d.ConnectEventEstablishRequestH\x00\x12.\n\x0b\x61\x63k_request\x18\x02 \x01(\x0b\x32\x17.ConnectEventAckRequestH\x00\x42\t\n\x07request\"O\n\x14\x43onnectEventResponse\x12\x0b\n\x03iid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x1c\n\targuments\x18\x03 \x03(\x0b\x32\t.Argument2\xae\x02\n\x14\x44ispatchProxyService\x12:\n\x0bGetDispatch\x12\x13.GetDispatchRequest\x1a\x14.GetDispatchResponse\"\x00\x12.\n\x07GetAttr\x12\x0f.GetAttrRequest\x1a\x10.GetAttrResponse\"\x00\x12.\n\x07SetAttr\x12\x0f.SetAttrRequest\x1a\x10.SetAttrResponse\"\x00\x12\x37\n\nCallMethod\x12\x12.CallMethodRequest\x1a\x13.CallMethodResponse\"\x00\x12\x41\n\x0c\x43onnectEvent\x12\x14.ConnectEventRequest\x1a\x15.ConnectEventResponse\"\x00(\x01\x30\x01\x62\x06proto3') - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'koapy.common.DispatchProxyService_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - _GETDISPATCHREQUEST._serialized_start=43 - _GETDISPATCHREQUEST._serialized_end=76 - _GETDISPATCHRESPONSE._serialized_start=78 - _GETDISPATCHRESPONSE._serialized_end=112 - _VALUE._serialized_start=115 - _VALUE._serialized_end=338 - _VALUEARRAY._serialized_start=340 - _VALUEARRAY._serialized_end=376 - _GETATTRREQUEST._serialized_start=378 - _GETATTRREQUEST._serialized_end=421 - _GETATTRRESPONSE._serialized_start=423 - _GETATTRRESPONSE._serialized_end=463 - _SETATTRREQUEST._serialized_start=465 - _SETATTRREQUEST._serialized_end=531 - _SETATTRRESPONSE._serialized_start=533 - _SETATTRRESPONSE._serialized_end=550 - _ARGUMENT._serialized_start=552 - _ARGUMENT._serialized_end=585 - _CALLMETHODREQUEST._serialized_start=587 - _CALLMETHODREQUEST._serialized_end=663 - _CALLMETHODRESPONSE._serialized_start=665 - _CALLMETHODRESPONSE._serialized_end=715 - _CONNECTEVENTESTABLISHREQUEST._serialized_start=717 - _CONNECTEVENTESTABLISHREQUEST._serialized_end=774 - _CONNECTEVENTACKREQUEST._serialized_start=776 - _CONNECTEVENTACKREQUEST._serialized_end=800 - _CONNECTEVENTREQUEST._serialized_start=803 - _CONNECTEVENTREQUEST._serialized_end=943 - _CONNECTEVENTRESPONSE._serialized_start=945 - _CONNECTEVENTRESPONSE._serialized_end=1024 - _DISPATCHPROXYSERVICE._serialized_start=1027 - _DISPATCHPROXYSERVICE._serialized_end=1329 -# @@protoc_insertion_point(module_scope) diff --git a/koapy/common/DispatchProxyService_pb2_grpc.py b/koapy/common/DispatchProxyService_pb2_grpc.py deleted file mode 100644 index 9908f3e5..00000000 --- a/koapy/common/DispatchProxyService_pb2_grpc.py +++ /dev/null @@ -1,198 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -from koapy.common import DispatchProxyService_pb2 as koapy_dot_common_dot_DispatchProxyService__pb2 - - -class DispatchProxyServiceStub(object): - """Missing associated documentation comment in .proto file.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.GetDispatch = channel.unary_unary( - '/DispatchProxyService/GetDispatch', - request_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchRequest.SerializeToString, - response_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchResponse.FromString, - ) - self.GetAttr = channel.unary_unary( - '/DispatchProxyService/GetAttr', - request_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrRequest.SerializeToString, - response_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrResponse.FromString, - ) - self.SetAttr = channel.unary_unary( - '/DispatchProxyService/SetAttr', - request_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrRequest.SerializeToString, - response_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrResponse.FromString, - ) - self.CallMethod = channel.unary_unary( - '/DispatchProxyService/CallMethod', - request_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodRequest.SerializeToString, - response_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodResponse.FromString, - ) - self.ConnectEvent = channel.stream_stream( - '/DispatchProxyService/ConnectEvent', - request_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventRequest.SerializeToString, - response_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventResponse.FromString, - ) - - -class DispatchProxyServiceServicer(object): - """Missing associated documentation comment in .proto file.""" - - def GetDispatch(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetAttr(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def SetAttr(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def CallMethod(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def ConnectEvent(self, request_iterator, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_DispatchProxyServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'GetDispatch': grpc.unary_unary_rpc_method_handler( - servicer.GetDispatch, - request_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchRequest.FromString, - response_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchResponse.SerializeToString, - ), - 'GetAttr': grpc.unary_unary_rpc_method_handler( - servicer.GetAttr, - request_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrRequest.FromString, - response_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrResponse.SerializeToString, - ), - 'SetAttr': grpc.unary_unary_rpc_method_handler( - servicer.SetAttr, - request_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrRequest.FromString, - response_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrResponse.SerializeToString, - ), - 'CallMethod': grpc.unary_unary_rpc_method_handler( - servicer.CallMethod, - request_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodRequest.FromString, - response_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodResponse.SerializeToString, - ), - 'ConnectEvent': grpc.stream_stream_rpc_method_handler( - servicer.ConnectEvent, - request_deserializer=koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventRequest.FromString, - response_serializer=koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'DispatchProxyService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) - - - # This class is part of an EXPERIMENTAL API. -class DispatchProxyService(object): - """Missing associated documentation comment in .proto file.""" - - @staticmethod - def GetDispatch(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/DispatchProxyService/GetDispatch', - koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchRequest.SerializeToString, - koapy_dot_common_dot_DispatchProxyService__pb2.GetDispatchResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def GetAttr(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/DispatchProxyService/GetAttr', - koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrRequest.SerializeToString, - koapy_dot_common_dot_DispatchProxyService__pb2.GetAttrResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def SetAttr(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/DispatchProxyService/SetAttr', - koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrRequest.SerializeToString, - koapy_dot_common_dot_DispatchProxyService__pb2.SetAttrResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def CallMethod(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/DispatchProxyService/CallMethod', - koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodRequest.SerializeToString, - koapy_dot_common_dot_DispatchProxyService__pb2.CallMethodResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def ConnectEvent(request_iterator, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.stream_stream(request_iterator, target, '/DispatchProxyService/ConnectEvent', - koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventRequest.SerializeToString, - koapy_dot_common_dot_DispatchProxyService__pb2.ConnectEventResponse.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/koapy/common/EventInstance.py b/koapy/common/EventInstance.py deleted file mode 100644 index a7cc580e..00000000 --- a/koapy/common/EventInstance.py +++ /dev/null @@ -1,37 +0,0 @@ -import warnings - -from threading import RLock -from typing import Any, Callable, Generic, List, Optional - -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec - -P = ParamSpec("P") - - -class EventInstance(Generic[P]): - def __init__(self): - self._lock = RLock() - self._slots: List[Callable[P, Any]] = [] - - def connect(self, slot: Callable[P, Any]): - with self._lock: - if slot not in self._slots: - self._slots.append(slot) - - def disconnect(self, slot: Optional[Callable[P, Any]] = None): - with self._lock: - if slot is None: - self._slots.clear() - elif slot in self._slots: - self._slots.remove(slot) - else: - warnings.warn("Tried to disconnect a slot that doesn't exist") - - def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None: - with self._lock: - slots = list(self._slots) - for slot in slots: - slot(*args, **kwargs) diff --git a/koapy/common/StubGenerator.py b/koapy/common/StubGenerator.py deleted file mode 100644 index 12a180bd..00000000 --- a/koapy/common/StubGenerator.py +++ /dev/null @@ -1,382 +0,0 @@ -import ast -import datetime - -import pythoncom - -from pythoncom import ProgIDFromCLSID -from pythoncom import com_error as PythonComError -from pywintypes import TimeType -from win32com.client.build import MakePublicAttributeName -from win32com.client.genpy import MakeEventMethodName - -from koapy.utils.pywin32 import BuildOleItems, GetLatestTypelibSpec - -comtype_to_annotation = { - pythoncom.VT_I2: int.__name__, - pythoncom.VT_I4: int.__name__, - pythoncom.VT_BOOL: bool.__name__, - pythoncom.VT_R8: float.__name__, - pythoncom.VT_BSTR: str.__name__, - pythoncom.VT_VARIANT: "Any", - pythoncom.VT_UNKNOWN: "Any", - pythoncom.VT_VOID: "None", -} - - -def make_args(entry, set_defaults=False): - fdesc = entry.desc - names = entry.names - num_args = len(fdesc[2]) - num_opt_args = fdesc[6] - if num_opt_args == -1: - num_args -= 1 - args = [ast.arg("self", None)] - defaults = [] - for i in range(num_args): - try: - arg_name = names[i + 1] - named_arg = arg_name is not None - except IndexError: - named_arg = False - if not named_arg: - arg_name = f"arg{i}" - arg_name = MakePublicAttributeName(arg_name) - arg_desc = fdesc[2][i] - arg_type = arg_desc[0] - arg_type = comtype_to_annotation[arg_type] - arg_annotation = ast.Name(arg_type, ast.Load()) - arg = ast.arg(arg_name, arg_annotation) - args.append(arg) - try: - arg_flag = arg_desc[1] - except IndexError: - arg_flag = pythoncom.PARAMFLAG_FIN - if arg_flag & pythoncom.PARAMFLAG_FHASDEFAULT: - arg_default = arg_desc[2] - if isinstance(arg_default, datetime.datetime): - arg_default = ast.Tuple( - [ast.Constant(v) for v in arg_default.utctimetuple()] - ) - elif isinstance(arg_default, TimeType): - arg_default = ast.Call( - ast.Name("Time", ast.Load()), - [ - ast.Constant(arg_default.year), - ast.Constant(arg_default.month), - ast.Constant(arg_default.day), - ast.Constant(arg_default.hour), - ast.Constant(arg_default.minute), - ast.Constant(arg_default.second), - ast.Constant(0), - ast.Constant(0), - ast.Constant(0), - ast.Constant(arg_default.msec), - ], - [], - ) - else: - arg_default = ast.Constant(arg_default) - else: - arg_default = None - if arg_default is None and set_defaults: - if ( - arg_desc[1] & (pythoncom.PARAMFLAG_FOUT | pythoncom.PARAMFLAG_FIN) - == pythoncom.PARAMFLAG_FOUT - ): - arg_default = ast.Name("Missing", ast.Load()) - else: - arg_default = ast.Name("Empty", ast.Load()) - defaults.append(arg_default) - if num_opt_args == -1: - vararg = ast.arg(names[-1], None) - else: - vararg = None - args = ast.arguments([], args, vararg, [], [], None, defaults) - return args - - -def make_method( - entry, - name=None, - is_getter=False, - is_setter=False, - is_event=False, - is_handler=False, -): - if not name: - name = entry.names[0] - if is_event or is_handler: - make_method_name = MakeEventMethodName - else: - make_method_name = MakePublicAttributeName - name = make_method_name(name) - if is_setter: - assert len(entry.desc.args) == 1 - elif is_getter: - assert len(entry.desc.args) == 0 - if is_getter: - args = [ast.arg("self", None)] - args = ast.arguments([], args, None, [], [], None, []) - elif is_setter: - arg_type = entry.desc.args[0][0] - arg_type = comtype_to_annotation[arg_type] - args = [ - ast.arg("self", None), - ast.arg(name, ast.Name(arg_type, ast.Load())), - ] - args = ast.arguments([], args, None, [], [], None, []) - else: - args = make_args(entry) - ellipsis_body = [ast.Expr(ast.Constant(Ellipsis))] - if is_event: - is_getter = True - if is_getter: - decorator_list = [ast.Name("property", ast.Load())] - elif is_setter: - decorator_list = [ - ast.Attribute(ast.Name(name, ast.Load()), "setter", ast.Load()) - ] - else: - decorator_list = [] - if is_event: - param_spec = ast.List([arg.annotation for arg in args.args[1:]], ast.Load()) - # cannot put [] in generic type args below version 3.10 - returns = ast.Subscript( - ast.Name("EventInstance", ast.Load()), - param_spec, - ast.Load(), - ) - # so just put without param spec - returns = ast.Name("EventInstance", ast.Load()) - # and add callable typing - callable_type = ast.Subscript( - ast.Name("Callable", ast.Load()), - ast.Tuple([param_spec, ast.Constant(None)], ast.Load()), - ) - # with union - returns = ast.Subscript( - ast.Name("Union", ast.Load()), - ast.Tuple([returns, callable_type], ast.Load()), - ast.Load(), - ) - else: - if is_getter and is_setter: - returns = ast.Name("Any", ast.Load()) - else: - return_type = entry.GetResultName() - if not return_type: - return_type = entry.desc.rettype[0] - return_type = comtype_to_annotation[return_type] - returns = ast.Name(return_type, ast.Load()) - if name == "__iter__": - returns = ast.Subscript( - ast.Name("Iterator", ast.Load()), returns, ast.Load() - ) - func_def = ast.FunctionDef(name, args, ellipsis_body, decorator_list, returns) - return func_def - - -def make_class_defs(ole_item): - class_defs = [] - - class_name = ole_item.python_name - is_sink = ole_item.bIsSink - - class_body = [] - class_body_assigns = [] - - clsid = ole_item.clsid - clsid_assign = ast.Assign( - [ast.Name("CLSID", ast.Store())], - ast.Call(ast.Name("IID", ast.Load()), [ast.Constant(str(clsid))], []), - ) - class_body_assigns.append(clsid_assign) - - try: - progid = ProgIDFromCLSID(clsid) - except PythonComError: - progid = None - - if progid: - progid_assign = ast.Assign( - [ast.Name("PROGID", ast.Store())], ast.Constant(progid) - ) - class_body_assigns.append(progid_assign) - - class_body.extend(class_body_assigns) - - if is_sink: - class_name = class_name.lstrip("_") - - if hasattr(ole_item, "mapFuncs"): - for name, entry in ole_item.mapFuncs.items(): - assert entry.desc.desckind == pythoncom.DESCKIND_FUNCDESC - if ( - entry.desc.wFuncFlags & pythoncom.FUNCFLAG_FRESTRICTED - and entry.desc.memid != pythoncom.DISPID_NEWENUM - ): - continue - if entry.desc.funckind != pythoncom.FUNC_DISPATCH: - continue - if entry.hidden: - continue - if entry.desc.memid == pythoncom.DISPID_VALUE: - name_lower = "value" - elif entry.desc.memid == pythoncom.DISPID_NEWENUM: - name_lower = "_newenum" - else: - name_lower = name.lower() - if name_lower == "count": - func_def = make_method(entry, "__len__") - elif name_lower == "item": - func_def = make_method(entry, "__getitem__") - elif name_lower == "value": - func_def = make_method(entry, "__call__") - elif name_lower == "_newenum": - func_def = make_method(entry, "__iter__") - else: - func_def = make_method(entry, is_event=is_sink) - class_body.append(func_def) - - if hasattr(ole_item, "propMap"): - for name, entry in ole_item.propMap.items(): - if entry.desc.memid == pythoncom.DISPID_VALUE: - name_lower = "value" - elif entry.desc.memid == pythoncom.DISPID_NEWENUM: - name_lower = "_newenum" - else: - name_lower = name.lower() - - if name_lower == "count": - func_def = make_method(entry, "__len__") - class_body.append(func_def) - elif name_lower == "item": - func_def = make_method(entry, "__getitem__") - class_body.append(func_def) - elif name_lower == "value": - func_def = make_method(entry, "__call__") - class_body.append(func_def) - elif name_lower == "_newenum": - func_def = make_method(entry, "__iter__") - class_body.append(func_def) - else: - func_def = make_method(entry, is_getter=True) - class_body.append(func_def) - - func_def = make_method(entry, is_setter=True) - class_body.append(func_def) - - if hasattr(ole_item, "propMapGet"): - for name, entry in ole_item.propMapGet.items(): - if entry.desc.memid == pythoncom.DISPID_VALUE: - name_lower = "value" - elif entry.desc.memid == pythoncom.DISPID_NEWENUM: - name_lower = "_newenum" - else: - name_lower = name.lower() - - if name_lower == "count": - func_def = make_method(entry, "__len__") - elif name_lower == "item": - func_def = make_method(entry, "__getitem__") - elif name_lower == "value": - func_def = make_method(entry, "__call__") - elif name_lower == "_newenum": - func_def = make_method(entry, "__iter__") - else: - func_def = make_method(entry, is_getter=True) - - class_body.append(func_def) - - if hasattr(ole_item, "propMapPut"): - for name, entry in ole_item.propMapPut.items(): - if name not in ole_item.propMap and name not in ole_item.propMapGet: - func_def = make_method(entry, is_getter=True, is_setter=True) - class_body.append(func_def) - - func_def = make_method(entry, is_setter=True) - class_body.append(func_def) - - if not class_body: - class_body = [ast.Expr(ast.Constant(Ellipsis))] - - class_bases = [] - - if hasattr(ole_item, "interfaces"): - class_bases_interfaces = [ - ast.Name(interface.python_name, ast.Load()) - for interface, flag in ole_item.interfaces - ] - class_bases.extend(class_bases_interfaces) - - if hasattr(ole_item, "sources"): - class_bases_sources = [ - ast.Name(source.python_name.lstrip("_"), ast.Load()) - for source, flag in ole_item.sources - ] - class_bases.extend(class_bases_sources) - - class_def = ast.ClassDef(class_name, class_bases, [], class_body, []) - class_defs.append(class_def) - - if is_sink: - class_name += "Handler" - - class_body = [] - class_body.extend(class_body_assigns) - - if hasattr(ole_item, "mapFuncs"): - for name, entry in ole_item.mapFuncs.items(): - assert entry.desc.desckind == pythoncom.DESCKIND_FUNCDESC - if ( - entry.desc.wFuncFlags & pythoncom.FUNCFLAG_FRESTRICTED - and entry.desc.memid != pythoncom.DISPID_NEWENUM - ): - continue - if entry.desc.funckind != pythoncom.FUNC_DISPATCH: - continue - if entry.hidden: - continue - if entry.desc.memid == pythoncom.DISPID_VALUE: - name_lower = "value" - elif entry.desc.memid == pythoncom.DISPID_NEWENUM: - name_lower = "_newenum" - else: - name_lower = name.lower() - if name_lower == "count": - continue - elif name_lower == "item": - continue - elif name_lower == "value": - continue - elif name_lower == "_newenum": - continue - else: - func_def = make_method(entry, is_handler=is_sink) - class_body.append(func_def) - - class_def = ast.ClassDef(class_name, [], [], class_body, []) - class_defs.append(class_def) - - return class_defs - - -def make_stub_module(clsid): - spec = GetLatestTypelibSpec(clsid) - ole_items, _, _, _ = BuildOleItems(spec) - import_froms = [ - ast.ImportFrom("collections.abc", [ast.alias("Iterator")], 0), - ast.ImportFrom( - "typing", [ast.alias("Any"), ast.alias("Callable"), ast.alias("Union")], 0 - ), - ast.ImportFrom("pythoncom", [ast.alias("Empty"), ast.alias("Missing")], 0), - ast.ImportFrom("pywintypes", [ast.alias("IID"), ast.alias("Time")], 0), - ast.ImportFrom("koapy.common", [ast.alias("EventInstance")], 0), - ] - class_defs = [] - for clsid, ole_item in ole_items.items(): - item_class_defs = make_class_defs(ole_item) - class_defs.extend(item_class_defs) - mod_body = import_froms + class_defs - mod = ast.Module(mod_body, []) - return mod diff --git a/koapy/common/__init__.py b/koapy/common/__init__.py deleted file mode 100644 index 6a3d994e..00000000 --- a/koapy/common/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .Dispatch import Dispatch -from .EventInstance import EventInstance diff --git a/koapy/common/tools/__init__.py b/koapy/common/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/common/tools/compile_proto.py b/koapy/common/tools/compile_proto.py deleted file mode 100644 index d26036c2..00000000 --- a/koapy/common/tools/compile_proto.py +++ /dev/null @@ -1,29 +0,0 @@ -import subprocess -import sys - -from pathlib import Path - - -def main(): - script_dir = Path(__file__).parent.resolve() - proto_filedir = script_dir.parent.resolve() - proto_filename = "DispatchProxyService.proto" - project_dir = proto_filedir.parent.parent.resolve() - proto_path = project_dir - python_out = project_dir - grpc_python_out = python_out - proto_filepath = proto_filedir / proto_filename - cmd = [ - sys.executable, - "-m", - "grpc_tools.protoc", - f"--proto_path={proto_path}", - f"--python_out={python_out}", - f"--grpc_python_out={grpc_python_out}", - f"{proto_filepath}", - ] - return subprocess.check_call(cmd, cwd=project_dir) - - -if __name__ == "__main__": - main() diff --git a/koapy/compat/__init__.py b/koapy/compat/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/compat/pyside2/QtAxContainer.py b/koapy/compat/pyside2/QtAxContainer.py deleted file mode 100644 index f0f6b82f..00000000 --- a/koapy/compat/pyside2/QtAxContainer.py +++ /dev/null @@ -1,8 +0,0 @@ -from . import PYQT5, PYSIDE2, PythonQtError - -if PYQT5: - from PyQt5.QAxContainer import * -elif PYSIDE2: - from PySide2.QtAxContainer import * -else: - raise PythonQtError("No Qt bindings could be found") diff --git a/koapy/compat/pyside2/QtCore.py b/koapy/compat/pyside2/QtCore.py deleted file mode 100644 index f0ecca0f..00000000 --- a/koapy/compat/pyside2/QtCore.py +++ /dev/null @@ -1 +0,0 @@ -from qtpy.QtCore import * diff --git a/koapy/compat/pyside2/QtGui.py b/koapy/compat/pyside2/QtGui.py deleted file mode 100644 index 74325c1e..00000000 --- a/koapy/compat/pyside2/QtGui.py +++ /dev/null @@ -1 +0,0 @@ -from qtpy.QtGui import * diff --git a/koapy/compat/pyside2/QtNetwork.py b/koapy/compat/pyside2/QtNetwork.py deleted file mode 100644 index 740fee99..00000000 --- a/koapy/compat/pyside2/QtNetwork.py +++ /dev/null @@ -1 +0,0 @@ -from qtpy.QtNetwork import * diff --git a/koapy/compat/pyside2/QtWidgets.py b/koapy/compat/pyside2/QtWidgets.py deleted file mode 100644 index 48874d77..00000000 --- a/koapy/compat/pyside2/QtWidgets.py +++ /dev/null @@ -1 +0,0 @@ -from qtpy.QtWidgets import * diff --git a/koapy/compat/pyside2/__init__.py b/koapy/compat/pyside2/__init__.py deleted file mode 100644 index 6e0a2da9..00000000 --- a/koapy/compat/pyside2/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -import os - -from koapy.config import config, debug -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - -# Set QT_API environment variable for correct Qt backend usage -os.environ["QT_API"] = config.get("koapy.qtpy.qt_api", "pyside2") - -# Import proper Qt binding using qtpy -from qtpy import * -from qtpy import PYQT5, PYSIDE2, PythonQtError - -# Check Qt backend -if PYQT5: - if debug: - logger.debug("Using PyQt5 as Qt backend") -elif PYSIDE2: - if debug: - logger.debug("Using PySide2 as Qt backend") -else: - raise PythonQtError("No Qt bindings could be found") - -# PySide2 patch -if PYSIDE2: - import PySide2 - - if hasattr(PySide2, "__file__"): - QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join( - os.path.dirname(PySide2.__file__), "plugins", "platforms" - ) - os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH diff --git a/koapy/compat/pywinauto/__init__.py b/koapy/compat/pywinauto/__init__.py deleted file mode 100644 index a5b95e2e..00000000 --- a/koapy/compat/pywinauto/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .importlib import PyWinAutoFinder - -PyWinAutoFinder.register() - -from pywinauto import * diff --git a/koapy/compat/pywinauto/findwindows.py b/koapy/compat/pywinauto/findwindows.py deleted file mode 100644 index 29a19681..00000000 --- a/koapy/compat/pywinauto/findwindows.py +++ /dev/null @@ -1 +0,0 @@ -from pywinauto.findwindows import * diff --git a/koapy/compat/pywinauto/importlib.py b/koapy/compat/pywinauto/importlib.py deleted file mode 100644 index 5214a61a..00000000 --- a/koapy/compat/pywinauto/importlib.py +++ /dev/null @@ -1,58 +0,0 @@ -import importlib -import sys -import warnings - -from importlib.abc import Loader, MetaPathFinder - -import pythoncom - - -class PyWinAutoFinder(MetaPathFinder): - def find_spec(self, fullname, path, target=None): - if fullname == "pywinauto": - self.unregister() - spec = importlib.util.find_spec(fullname) - spec.loader = PyWinAutoLoader() - return spec - - @classmethod - def register(cls): - sys.meta_path = [cls()] + sys.meta_path - - @classmethod - def unregister(cls): - sys.meta_path = [x for x in sys.meta_path if not isinstance(x, cls)] - - -class PyWinAutoLoader(Loader): - def __init__(self): - self._original_coinit_flags_defined = False - self._original_coinit_flags = None - - def set_sys_coinit_flags(self): - self._original_coinit_flags_defined = hasattr(sys, "coinit_flags") - self._original_coinit_flags = getattr(sys, "coinit_flags", None) - sys.coinit_flags = pythoncom.COINIT_APARTMENTTHREADED - - def reset_sys_coinit_flags(self): - if not self._original_coinit_flags_defined: - del sys.coinit_flags - else: - sys.coinit_flags = self._original_coinit_flags - - def create_module(self, spec): - # set sys.coinit_flags = 2 - # check https://github.com/pywinauto/pywinauto/issues/472 for more information - self.set_sys_coinit_flags() - - # ensure that qt binding is imported before pywinauto import - from koapy.compat import pyside2 - - # import pywinauto - with warnings.catch_warnings(): - warnings.simplefilter("ignore", UserWarning) - module = importlib.import_module(spec.name) - return module - - def exec_module(self, module): - pass diff --git a/koapy/compat/pywinauto/timings.py b/koapy/compat/pywinauto/timings.py deleted file mode 100644 index 79d9f3d9..00000000 --- a/koapy/compat/pywinauto/timings.py +++ /dev/null @@ -1 +0,0 @@ -from pywinauto.timings import * diff --git a/koapy/config.conf b/koapy/config.conf deleted file mode 100644 index 3ca79132..00000000 --- a/koapy/config.conf +++ /dev/null @@ -1,76 +0,0 @@ -{ - koapy.qtpy.qt_api = "pyside2" - koapy.python.executable { - 32bit = { conda = "x86" } - 64bit = { path = "python" } - } - koapy.backend.kiwoom_open_api_plus.grpc { - host = "localhost" - port = 5943 - server { - host = "localhost" - bind_address = "localhost" - port = 5943 - max_workers = 8 - channel.credentials.ssl { - key_file = null - cert_file = null - root_certs_file = null - require_client_auth = false - } - } - client { - host = "localhost" - port = 5943 - max_workers = 8 - is_ready.timeout = 10 - channel.credentials.ssl { - enable_ssl = false - require_server_auth = false - key_file = null - cert_file = null - root_certs_file = null - } - } - } - koapy.backend.kiwoom_open_api_plus.credentials { - user_id = "" - user_password = "" - cert_password = "" - is_simulation = true - account_passwords {} - } - koapy.backend.daishin_cybos_plus.credentials { - user_id = "" - user_password = "" - cert_password = "" - auto_account_password = true - auto_cert_password = true - price_check_only = true - account_passwords {} - } - koapy.utils.logging.config { - version = 1 - formatters { - default { - format = "%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d" - } - } - handlers { - console { - class = "koapy.utils.logging.tqdm.TqdmStreamHandler.TqdmStreamHandler" - level = "NOTSET" - formatter = "default" - } - } - loggers { - koapy { - level = "DEBUG" - propagate = false - handlers = ["console"] - } - } - incremental = false - disable_existing_loggers = false - } -} \ No newline at end of file diff --git a/koapy/config.py b/koapy/config.py deleted file mode 100644 index 2d7283e6..00000000 --- a/koapy/config.py +++ /dev/null @@ -1,311 +0,0 @@ -import shutil -import subprocess -import sys - -from os import PathLike -from pathlib import Path -from typing import Any, Mapping, Optional, Union - -from pyhocon import ConfigFactory -from pyhocon.config_tree import ConfigTree -from pyhocon.converter import HOCONConverter - -from koapy.utils.platform import is_32bit, is_64bit - -# Type alias for config object -Config = ConfigTree - - -# Paths related to default config file -# bundled with this package for fallback -default_config_filename = "config.conf" -default_config_file_directory = Path(__file__).parent -default_config_filepath = default_config_file_directory / default_config_filename - - -# Paths related to user config file -# for use customization -current_working_directory = Path.cwd() -home_directory = Path.home() - -default_user_config_filename = "koapy.conf" - -user_config_filename_cadidates = [ - default_user_config_filename, - "." + default_user_config_filename, -] - -default_user_config_filepath = home_directory / default_user_config_filename - - -# Default encoding for all file read/writes across this package -default_encoding = "utf-8" - - -# Function for reading configs -def read_config( - filename: Optional[Union[PathLike, str]] = None, - encoding: Optional[str] = None, -) -> Config: - if filename is None: - filename = default_user_config_filepath - if isinstance(filename, str): - filename = Path(filename) - if encoding is None: - encoding = default_encoding - # pylint: disable=redefined-outer-name - config = ConfigFactory.parse_file(filename, encoding=encoding) - return config - - -# Function for create configs from dict -def config_from_dict(dictionary: Mapping[str, Any]) -> Config: - # pylint: disable=redefined-outer-name - config = ConfigFactory.from_dict(dictionary) - return config - - -# Load default config bundled with this package for fallback -default_config = read_config(default_config_filepath) - - -# Try to read user config file from candidate paths -# 1. Starting from current directory, search for a user config file until reaching the root directory, with specific name patterns -# 2. In terms of user config filename pattern, visible filename takes precedence to hidden filename (hidden that starts with a dot) -# 3. If fails to find a user config file even in the root directory, finally check user home directory for a user config file - - -# Search for a user config file in a given directory -def find_user_config_file_in( - searching_directory: Optional[Union[PathLike, str]] = None, -) -> Optional[Path]: - if searching_directory is None: - # pylint: disable=redefined-outer-name - current_working_directory = Path.cwd() - searching_directory = current_working_directory - searching_directory_path = Path(searching_directory).resolve() - for config_filename in user_config_filename_cadidates: - config_filepath = searching_directory_path / config_filename - if config_filepath.exists(): - return config_filepath - - -# Search for a user config file from a given directory to the root directory -def find_user_config_file_from( - starting_directory: Optional[Union[PathLike, str]] = None, -) -> Optional[Path]: - if starting_directory is None: - # pylint: disable=redefined-outer-name - current_working_directory = Path.cwd() - starting_directory = current_working_directory - searching_directory_path = Path(starting_directory).resolve() - should_stop = False - while not should_stop: - config_filepath = find_user_config_file_in(searching_directory_path) - if config_filepath: - return config_filepath - has_no_more_parent = ( - str(searching_directory_path) == searching_directory_path.anchor - ) - should_stop = has_no_more_parent - searching_directory_path = searching_directory_path.parent - - -# Empty config for internal usage -empty_config = config_from_dict({}) - -# Prepare user config before reading actual user config file (which may not exist) -user_config = empty_config - -# Main config object for general use -# User config takes precedence and fallbacks to default config for missing entries -config = user_config.with_fallback(default_config) - - -# Helper function for updating `user_config`, mostly for internal use -# This also consequently updates `config` global variable -def set_user_config(c: Config) -> Config: - global user_config # pylint: disable=global-statement - global config # pylint: disable=global-statement - user_config = c - config = user_config.with_fallback(default_config) - return user_config - - -# Function for config initialization -def initialize_config_from_given_path( - filename: Optional[Union[PathLike, str]] = None -) -> bool: - user_config_filepath: Optional[PathLike] = None - initialized = False - - # Use given filepath if possible - if not user_config_filepath: - if filename: - filepath = Path(filename).resolve() - if filepath.exists(): - user_config_filepath = filepath - - if user_config_filepath: - # pylint: disable=redefined-outer-name - user_config = read_config(user_config_filepath) - set_user_config(user_config) - initialized = True - - return initialized - - -# Function for config initialization -def initialize_config_from_expected_paths() -> bool: - user_config_filepath: Optional[PathLike] = None - initialized = False - - # Try searching starting from current directory to root - if not user_config_filepath: - user_config_filepath = find_user_config_file_from(current_working_directory) - - # Try searching in home directory - if not user_config_filepath: - user_config_filepath = find_user_config_file_in(home_directory) - - # If user config file is found, read the config file - # This overwrites previously declared emtpy `user_config` global variable - if user_config_filepath: - # pylint: disable=redefined-outer-name - user_config = read_config(user_config_filepath) - set_user_config(user_config) - initialized = True - - return initialized - - -# Just run basic initializtion for the first time -initialize_config_from_expected_paths() - - -# Simple helper function for getting config -def get_config() -> Config: - return config - - -# Simple helper function for getting user config -def get_user_config() -> Config: - return user_config - - -# Flag value for additional logging for debugging purpose (mainly in development process) -debug = False - - -# Dump config object to string -def dump_config( - config: Config, - compact: bool = False, - indent: int = 4, -) -> str: - # pylint: disable=redefined-outer-name - hocon = HOCONConverter.to_hocon(config, compact=compact, indent=indent) - return hocon - - -# Save config to file -def save_config( - filename: Union[PathLike, str], - config: Optional[Config] = None, - compact: bool = False, - indent: int = 4, - encoding: Optional[str] = None, -): - # pylint: disable=redefined-outer-name - if config is None: - config = get_config() - if encoding is None: - encoding = default_encoding - hocon = dump_config(config, compact=compact, indent=indent) - with open(filename, "w", encoding=encoding) as f: - f.write(hocon) - - -# Save user config to file (without default fallbacks) -def save_user_config( - filename: Optional[Union[PathLike, str]] = None, - user_config: Optional[Config] = None, - compact: bool = False, - indent: int = 4, - encoding: Optional[str] = None, -): - # pylint: disable=redefined-outer-name - if filename is None: - filename = default_user_config_filepath - if user_config is None: - user_config = get_user_config() - if encoding is None: - encoding = default_encoding - save_config(filename, user_config, compact, indent, encoding) - - -# Helper functions for getting python executables below -def get_executable_from_conda_envname(envname: str) -> str: - return subprocess.check_output( - [ - "conda", - "run", - "-n", - envname, - "python", - "-c", - "import sys; print(sys.executable)", - ], - encoding=sys.stdout.encoding, - creationflags=subprocess.CREATE_NO_WINDOW, - ).strip() - - -def get_executable_from_conda_envpath(envpath: str) -> str: - return subprocess.check_output( - [ - "conda", - "run", - "-p", - envpath, - "python", - "-c", - "import sys; print(sys.executable)", - ], - encoding=sys.stdout.encoding, - creationflags=subprocess.CREATE_NO_WINDOW, - ).strip() - - -def get_executable_from_executable_config(executable_config: Config) -> Optional[str]: - if isinstance(executable_config, str): - return executable_config - if isinstance(executable_config, dict): - if "path" in executable_config: - return executable_config["path"] - if "conda" in executable_config and shutil.which("conda") is not None: - conda_config = executable_config["conda"] - if isinstance(conda_config, str): - envname = conda_config - return get_executable_from_conda_envname(envname) - if isinstance(conda_config, dict): - if "name" in conda_config: - envname = conda_config["name"] - return get_executable_from_conda_envname(envname) - if "path" in conda_config: - envpath = conda_config["path"] - return get_executable_from_conda_envpath(envpath) - - -def get_32bit_executable() -> Optional[str]: - if is_32bit(): - return sys.executable - executable_config = config.get("koapy.python.executable.32bit") - return get_executable_from_executable_config(executable_config) - - -def get_64bit_executable() -> Optional[str]: - if is_64bit(): - return sys.executable - executable_config = config.get("koapy.python.executable.64bit") - return get_executable_from_executable_config(executable_config) diff --git a/koapy/examples/00_roll_your_own_pyqt5.py b/koapy/examples/00_roll_your_own_pyqt5.py deleted file mode 100644 index 319bf7d5..00000000 --- a/koapy/examples/00_roll_your_own_pyqt5.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys - -from PyQt5.QAxContainer import QAxWidget -from PyQt5.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}") - -APIModulePath = control.dynamicCall("GetAPIModulePath()") - -print(APIModulePath) diff --git a/koapy/examples/00_roll_your_own_pyside2.py b/koapy/examples/00_roll_your_own_pyside2.py deleted file mode 100644 index 04f197d7..00000000 --- a/koapy/examples/00_roll_your_own_pyside2.py +++ /dev/null @@ -1,20 +0,0 @@ -import os - -import PySide2 - -QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join( - os.path.dirname(PySide2.__file__), "plugins", "platforms" -) -os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH - -import sys - -from PySide2.QtAxContainer import QAxWidget -from PySide2.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}") - -APIModulePath = control.dynamicCall("GetAPIModulePath()") - -print(APIModulePath) diff --git a/koapy/examples/01_roll_your_own_koapy.py b/koapy/examples/01_roll_your_own_koapy.py deleted file mode 100644 index 24fddb4b..00000000 --- a/koapy/examples/01_roll_your_own_koapy.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys - -from koapy import KiwoomOpenApiPlusQAxWidget -from koapy.compat.pyside2.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = KiwoomOpenApiPlusQAxWidget() - -APIModulePath = control.GetAPIModulePath() - -print(APIModulePath) diff --git a/koapy/examples/02_roll_your_own_event_pyqt5.py b/koapy/examples/02_roll_your_own_event_pyqt5.py deleted file mode 100644 index cebb8652..00000000 --- a/koapy/examples/02_roll_your_own_event_pyqt5.py +++ /dev/null @@ -1,109 +0,0 @@ -import sys - -from PyQt5.QAxContainer import QAxWidget -from PyQt5.QtCore import QEventLoop -from PyQt5.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}") - -loop = QEventLoop() - - -def comm_connect(): - err = control.dynamicCall("CommConnect()") - if err < 0: - raise ValueError(err) - loop.exec_() - - -def on_event_connect(errcode): - if errcode < 0: - raise ValueError(errcode) - if errcode == 0: - print("Connected!") - control.OnEventConnect.disconnect(on_event_connect) - loop.exit() - - -control.OnEventConnect.connect(on_event_connect) - -comm_connect() - - -def get_stock_info(code): - rqname = "get_stock_info" - trcode = "opt10001" - prevnext = 0 - screenno = "0001" - control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - prevnext, - screenno, - ) - if err < 0: - raise ValueError(err) - loop.exec_() - - -code = "005930" -price = 0 - - -def on_receive_tr_data( - scrno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg -): - global price - - # single data - index = 0 - itemname = "현재가" - price = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - - # multi data - repeat_cnt = control.dynamicCall( - "GetRepeatCnt(const QString&, const QString&)", trcode, recordname - ) - if repeat_cnt > 0: - prices = [] - for index in range(repeat_cnt): - price_index = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - prices.append(price_index) - - if prevnext not in ["", "0"]: - control.dynamicCall( - "SetInputValue(const QString&, const QString&)", "종목코드", code - ) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - int(prevnext), - scrno, - ) - if err < 0: - raise ValueError(err) - else: - control.OnReceiveTrData.disconnect(on_receive_tr_data) - loop.exit() - - -control.OnReceiveTrData.connect(on_receive_tr_data) -get_stock_info(code) - -print(price) diff --git a/koapy/examples/02_roll_your_own_event_pyside2.py b/koapy/examples/02_roll_your_own_event_pyside2.py deleted file mode 100644 index 1d0adc4f..00000000 --- a/koapy/examples/02_roll_your_own_event_pyside2.py +++ /dev/null @@ -1,125 +0,0 @@ -import os - -import PySide2 - -QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join( - os.path.dirname(PySide2.__file__), "plugins", "platforms" -) -os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH - -import sys - -from PySide2.QtAxContainer import QAxWidget -from PySide2.QtCore import SIGNAL, QEventLoop -from PySide2.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}") - -loop = QEventLoop() - - -def comm_connect(): - err = control.dynamicCall("CommConnect()") - if err < 0: - raise ValueError(err) - loop.exec_() - - -on_event_connect_signal = SIGNAL("OnEventConnect(int)") - - -def on_event_connect(errcode): - if errcode < 0: - raise ValueError(errcode) - if errcode == 0: - print("Connected!") - control.disconnect(on_event_connect_signal, on_event_connect) - loop.exit() - - -control.connect(on_event_connect_signal, on_event_connect) - -comm_connect() - - -def get_stock_info(code): - rqname = "get_stock_info" - trcode = "opt10001" - prevnext = 0 - screenno = "0001" - control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - prevnext, - screenno, - ) - if err < 0: - raise ValueError(err) - loop.exec_() - - -code = "005930" -price = 0 - -on_receive_tr_data_signal = SIGNAL( - "OnReceiveTrData(const QString&, const QString&, const QString&, const QString&, const QString&, int, const QString&, const QString&, const QString&)" -) - - -def on_receive_tr_data( - scrno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg -): - global price - - # single data - index = 0 - itemname = "현재가" - price = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - - # multi data - repeat_cnt = control.dynamicCall( - "GetRepeatCnt(const QString&, const QString&)", trcode, recordname - ) - if repeat_cnt > 0: - prices = [] - for index in range(repeat_cnt): - price_index = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - prices.append(price_index) - - if prevnext not in ["", "0"]: - control.dynamicCall( - "SetInputValue(const QString&, const QString&)", "종목코드", code - ) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - int(prevnext), - scrno, - ) - if err < 0: - raise ValueError(err) - else: - control.disconnect(on_receive_tr_data_signal, on_receive_tr_data) - loop.exit() - - -control.connect(on_receive_tr_data_signal, on_receive_tr_data) -get_stock_info(code) - -print(price) diff --git a/koapy/examples/03_roll_your_own_event_koapy.py b/koapy/examples/03_roll_your_own_event_koapy.py deleted file mode 100644 index c8414208..00000000 --- a/koapy/examples/03_roll_your_own_event_koapy.py +++ /dev/null @@ -1,109 +0,0 @@ -import sys - -from koapy import KiwoomOpenApiPlusQAxWidget -from koapy.compat.pyside2.QtCore import QEventLoop -from koapy.compat.pyside2.QtWidgets import QApplication - -app = QApplication(sys.argv) -control = KiwoomOpenApiPlusQAxWidget() - -loop = QEventLoop() - - -def comm_connect(): - err = control.dynamicCall("CommConnect()") - if err < 0: - raise ValueError(err) - loop.exec_() - - -def on_event_connect(errcode): - if errcode < 0: - raise ValueError(errcode) - if errcode == 0: - print("Connected!") - control.OnEventConnect.disconnect(on_event_connect) - loop.exit() - - -control.OnEventConnect.connect(on_event_connect) - -comm_connect() - - -def get_stock_info(code): - rqname = "get_stock_info" - trcode = "opt10001" - prevnext = 0 - screenno = "0001" - control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - prevnext, - screenno, - ) - if err < 0: - raise ValueError(err) - loop.exec_() - - -code = "005930" -price = 0 - - -def on_receive_tr_data( - scrno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg -): - global price - - # single data - index = 0 - itemname = "현재가" - price = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - - # multi data - repeat_cnt = control.dynamicCall( - "GetRepeatCnt(const QString&, const QString&)", trcode, recordname - ) - if repeat_cnt > 0: - prices = [] - for index in range(repeat_cnt): - price_index = control.dynamicCall( - "GetCommData(const QString&, const QString&, int, const QString&)", - trcode, - recordname, - index, - itemname, - ).strip() - prices.append(price_index) - - if prevnext not in ["", "0"]: - control.dynamicCall( - "SetInputValue(const QString&, const QString&)", "종목코드", code - ) - err = control.dynamicCall( - "CommRqData(const QString&, const QString&, int, const QString&)", - rqname, - trcode, - int(prevnext), - scrno, - ) - if err < 0: - raise ValueError(err) - else: - control.OnReceiveTrData.disconnect(on_receive_tr_data) - loop.exit() - - -control.OnReceiveTrData.connect(on_receive_tr_data) -get_stock_info(code) - -print(price) diff --git a/koapy/examples/04_koapy_tray_application.py b/koapy/examples/04_koapy_tray_application.py deleted file mode 100644 index 68a6312d..00000000 --- a/koapy/examples/04_koapy_tray_application.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys - -from koapy import KiwoomOpenApiPlusManagerApplication - -KiwoomOpenApiPlusManagerApplication.main(sys.argv) diff --git a/koapy/examples/05_koapy_entrypoint.py b/koapy/examples/05_koapy_entrypoint.py deleted file mode 100644 index b523d9f4..00000000 --- a/koapy/examples/05_koapy_entrypoint.py +++ /dev/null @@ -1,19 +0,0 @@ -# Test this example script with two different scenarios -# -# 1. External-Server-Process scenario -# 1. Run 04_koapy_tray_application.py script in 32bit environment -# => Server will start with tray application -# 2. Open another console and run 05_koapy_entrypoint.py script (this one), in 32bit or 64bit environment -# => Client will connect to the existing server -# -# 2. Server-In-Subprocess scenario -# 1. Just run 05_koapy_entrypoint.py script (this one) in 32bit environment -# => Server will start in subprocess and Client will connect to it - -from koapy import KiwoomOpenApiPlusEntrypoint - -entrypoint = KiwoomOpenApiPlusEntrypoint() - -APIModulePath = entrypoint.GetAPIModulePath() - -print(APIModulePath) diff --git a/koapy/examples/06_main_scenario.py b/koapy/examples/06_main_scenario.py deleted file mode 100644 index 0765d0aa..00000000 --- a/koapy/examples/06_main_scenario.py +++ /dev/null @@ -1,236 +0,0 @@ -# 로깅 설정 -import logging - -logging.basicConfig( - format="%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - level=logging.DEBUG, -) - -# KOAPY 임포트 -from koapy import KiwoomOpenApiPlusEntrypoint - -# 1. 엔트리포인트 객체 생성 -entrypoint = KiwoomOpenApiPlusEntrypoint() - -# 모듈 경로 확인 (기본 함수 사용 예시) -module_path = entrypoint.GetAPIModulePath() -print(module_path) - -# 2. 로그인 예시 -logging.info("Logging in...") -entrypoint.EnsureConnected() -logging.info("Logged in.") - -# 3. 기본 함수 실행 예시 - -# 접속 상태 확인 (기본 함수 호출 예시) -logging.info("Checking connection status...") -status = entrypoint.GetConnectState() -logging.info("Connection status: %s", status) - -# 종목 리스트 확인 (기본 함수 호출 예시) -logging.info("Getting stock codes and names...") -codes = entrypoint.GetCodeListByMarketAsList("0") -names = [entrypoint.GetMasterCodeName(code) for code in codes] - -# 위에서 가져온 정보로 삼성전자의 code 확인 -codes_by_name = dict(zip(names, codes)) -logging.info("Checking stock code of Samsung...") -code = samsung_code = codes_by_name["삼성전자"] -logging.info("Code of Samsung: %s", code) - -# 4. TR 요청 예시 - -# 상위 함수를 활용한 TR 요청 예시 (opt10001) -logging.info("Getting basic info of Samsung...") -info = entrypoint.GetStockBasicInfoAsDict(code) -logging.info("Got basic info data (using GetStockBasicInfoAsDict):") -print(info) - -# 상위 함수를 활용한 TR 요청 예시 (opt10081) -logging.info("Getting daily stock data of Samsung...") -data = entrypoint.GetDailyStockDataAsDataFrame(code) -logging.info("Got daily stock data:") -print(data) - -# 하위 함수를 사용한 TR 요청 예시 (opt10001) -rqname = "주식기본정보요청" -trcode = "opt10001" -screen_no = "0001" # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당 -inputs = {"종목코드": code} - -output = {} - -logging.info("Requesting data for request name: %s", rqname) -for event in entrypoint.TransactionCall(rqname, trcode, screen_no, inputs): - logging.info("Got event for request: %s", rqname) - names = event.single_data.names - values = event.single_data.values - for name, value in zip(names, values): - output[name] = value - -logging.info("Got basic info data (using TransactionCall):") -print(output) - -# (디버깅을 위한) 이벤트 메시지 출력 함수 -from pprint import PrettyPrinter - -from google.protobuf.json_format import MessageToDict - -pp = PrettyPrinter() - - -def pprint_event(event): - pp.pprint(MessageToDict(event, preserving_proto_field_name=True)) - - -logging.info("Last event message was:") -pprint_event(event) - -# TR 관련 메타정보 확인 -from koapy import KiwoomOpenApiPlusTrInfo - -logging.info("Checking TR info of opt10001") -tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001") - -logging.info("Inputs of opt10001:") -print(tr_info.inputs) -logging.info("Single outputs of opt10001:") -print(tr_info.single_outputs) -logging.info("Multi outputs of opt10001:") -print(tr_info.multi_outputs) - -# 5. 조건검색 예시 - -# 조건검색 설정 불러오기 -entrypoint.EnsureConditionLoaded() - -# 일반 조건검색 예시 -condition_name = "대형 저평가 우량주" - -logging.info("Getting stock codes with condition: %s", condition_name) -codes, info = entrypoint.GetCodeListByCondition(condition_name, with_info=True) - -print(codes) -print(info) - -# 실시간 조건검색 예시 -condition_name = "중소형 저평가주" - -logging.info("Start listening realtime condition stream...") -stream = entrypoint.GetCodeListByConditionAsStream(condition_name) - -# 이벤트 스트림을 도중에 멈추기 위해서 threading.Timer 활용 -import threading - - -def stop_listening_cond(): - logging.info("Stop listening realtime condition events...") - stream.cancel() - - -threading.Timer(10.0, stop_listening_cond).start() # 10초 이후에 gRPC 커넥션 종료하도록 설정 - -# 이벤트 불러와서 출력처리 -import grpc - -try: - for event in stream: - pprint_event(event) -except grpc.RpcError as e: - pass - -# 6.주문처리 예시 - -from exchange_calendars import get_calendar - -# 현재 시장이 열려 있는지 (주문이 가능한지) 확인하는 함수 -from pandas import Timestamp - -krx_calendar = get_calendar("XKRX") - - -def is_currently_in_session(): - now = Timestamp.now(tz=krx_calendar.tz) - previous_open = krx_calendar.previous_open(now).astimezone(krx_calendar.tz) - next_close = krx_calendar.next_close(previous_open).astimezone(krx_calendar.tz) - return previous_open <= now <= next_close - - -# 주문처리 파라미터 설정 -first_account_no = entrypoint.GetFirstAvailableAccount() - -request_name = "삼성전자 1주 시장가 신규 매수" # 사용자 구분명, 구분가능한 임의의 문자열 -screen_no = "0001" # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당 -account_no = first_account_no # 계좌번호 10자리, 여기서는 계좌번호 목록에서 첫번째로 발견한 계좌번호로 매수처리 -order_type = 1 # 주문유형, 1 : 신규매수 -code = samsung_code # 종목코드, 앞의 삼성전자 종목코드 -quantity = 1 # 주문수량, 1주 매수 -price = 0 # 주문가격, 시장가 매수는 가격설정 의미없음 -quote_type = "03" # 거래구분, 03 : 시장가 -original_order_no = "" # 원주문번호, 주문 정정/취소 등에서 사용 - -# 현재는 기본적으로 주문수량이 모두 소진되기 전까지 이벤트를 듣도록 되어있음 (단순 호출 예시) -if is_currently_in_session(): - logging.info( - "Sending order to buy %s, quantity of 1 stock, at market price...", code - ) - for event in entrypoint.OrderCall( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - ): - pprint_event(event) -else: - logging.info("Cannot send an order while market is not open, skipping...") - -# 7. 실시간 데이터 처리 예시 -from koapy import KiwoomOpenApiPlusRealType - -code_list = [code] -fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세") -opt_type = "0" # 기존 화면에 추가가 아니라 신규 생성 - -# 현재는 기본적으로 실시간 이벤트를 무한정 가져옴 (커넥션 컨트롤 가능한 예시) -logging.info("Starting to get realtime stock data for code: %s", code) -stream = entrypoint.GetRealDataForCodesAsStream( - code_list, - fid_list, - opt_type, - screen_no=None, # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당 - infer_fids=True, # True 로 설정 시 주어진 fid_list 를 고집하지 말고 이벤트 처리 함수의 인자로 전달받는 실시간데이터 이름에 따라 유연하게 fid_list 를 추론 - readable_names=True, # True 로 설정 시 각 fid 마다 숫자 대신 읽을 수 있는 이름으로 변환하여 반환 - fast_parse=False, # True 로 설정 시 이벤트 처리 함수내에서 데이터 값 읽기 시 GetCommRealData() 함수 호출 대신, 이벤트 처리 함수의 인자로 넘어오는 데이터를 직접 활용, infer_fids 가 True 로 설정된 경우만 유의미함 -) - -# 이벤트 스트림을 도중에 멈추기 위해서 threading.Timer 활용 -import threading - - -def stop_listening_real(): - logging.info("Stop listening realtime events...") - stream.cancel() - - -threading.Timer(10.0, stop_listening_real).start() # 10초 이후에 gRPC 커넥션 종료하도록 설정 - -# 이벤트 불러와서 출력처리 -import grpc - -try: - for event in stream: - pprint_event(event) -except grpc.RpcError as e: - print(e) - -# 예시 스크립트 끝 -logging.info("End of example") - -# 리소스 해제 -entrypoint.close() diff --git a/koapy/examples/07_transaction_event.py b/koapy/examples/07_transaction_event.py deleted file mode 100644 index b9228f8c..00000000 --- a/koapy/examples/07_transaction_event.py +++ /dev/null @@ -1,34 +0,0 @@ -from koapy import KiwoomOpenApiPlusEntrypoint - -with KiwoomOpenApiPlusEntrypoint() as context: - # 로그인 처리 - context.EnsureConnected() - - # 이벤트를 알아서 처리하고 결과물만 제공하는 상위 함수 사용 예시 - code = "005930" - info = context.GetStockBasicInfoAsDict(code) - print(info) - price = info["현재가"] - print(price) - - # 이벤트를 스트림으로 반환하는 하위 함수 직접 사용 예시 (위의 상위 함수 내부에서 실제로 처리되는 내용에 해당) - rqname = "주식기본정보요청" - trcode = "opt10001" - screenno = "0001" - inputs = {"종목코드": code} - output = {} - - # 아래의 함수는 gRPC 서비스의 rpc 함수를 직접 호출함 - # 따라서 event 메시지의 구조는 koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto 파일 참조 - for event in context.TransactionCall(rqname, trcode, screenno, inputs): - names = event.single_data.names - values = event.single_data.values - for name, value in zip(names, values): - output[name] = value - - # 전체 결과 출력 (싱글데이터) - print(output) - - # 현재가 값만 출력 - price = output["현재가"] - print(price) diff --git a/koapy/examples/08_check_account_status.py b/koapy/examples/08_check_account_status.py deleted file mode 100644 index b390d3b4..00000000 --- a/koapy/examples/08_check_account_status.py +++ /dev/null @@ -1,41 +0,0 @@ -from koapy import KiwoomOpenApiPlusEntrypoint - -with KiwoomOpenApiPlusEntrypoint() as context: - context.EnsureConnected() - - account_nos = context.GetAccountList() - print("전체 계좌 목록: %s" % account_nos) - - account_no = account_nos[0] - print("사용할 계좌번호: %s" % account_no) - print() - - series = context.GetDepositInfo(account_no) - print("예수금상세현황요청 : 예수금상세현황") - print(series.to_markdown()) - print() - - df = context.GetAccountRateOfReturnAsDataFrame(account_no) - print("계좌수익률요청 : 계좌수익률") # TR 이름에서 그대로 따왔긴 한데, 정작 수익률은 그 어디에도 없음.. - print(df.to_markdown()) - print() - - summary, foreach = context.GetAccountEvaluationStatusAsSeriesAndDataFrame( - account_no - ) - print("계좌평가현황요청 : 계좌평가현황") - print(summary.to_markdown()) - print("계좌평가현황요청 : 종목별계좌평가현황") - print(foreach.to_markdown()) - print() - - # 위와 아래의 차이는 수수료/세금 영향을 고려하냐 안하냐의 차이인듯, 위는 고려하지 않고 아래는 모두 고려하는것으로 보임 - - summary, foreach = context.GetAccountEvaluationBalanceAsSeriesAndDataFrame( - account_no - ) - print("계좌평가잔고내역요청 : 계좌평가결과") - print(summary.to_markdown(disable_numparse=True)) - print("계좌평가잔고내역요청 : 계좌평가잔고개별합산") - print(foreach.to_markdown()) - print() diff --git a/koapy/examples/09_get_historical_data.py b/koapy/examples/09_get_historical_data.py deleted file mode 100644 index 5bfe650c..00000000 --- a/koapy/examples/09_get_historical_data.py +++ /dev/null @@ -1,77 +0,0 @@ -import logging - -logging.basicConfig( - format="%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - level=logging.DEBUG, -) - -import datetime - -from exchange_calendars import get_calendar - -from koapy import KiwoomOpenApiPlusEntrypoint - -krx_calendar = get_calendar("XKRX") - -with KiwoomOpenApiPlusEntrypoint() as context: - # 로그인 처리 - context.EnsureConnected() - - # 종목코드 - code = "005930" - - # 가장 최근 날짜 - start_date = datetime.datetime.now() - - # 날짜 값은 datetime.datetime 타입도 되고 문자열도 됨 - # 문자열 포맷은 구체적으로, 일봉위로는 YYYYMMDD 포맷, 분봉아래로는 YYYYMMDDhhmmss 포맷 지원 - - # 가장 오래된 날짜 (거래소 개장일 기준 30일 전) - end_date = start_date - 30 * krx_calendar.day - - # 참고로 end_date 은 주어진 시간보다 큰 (같지 않은) 레코드만 가져오도록 구현되어있기 때문에 설정에 주의 - # 일반적으로 해당 날짜는 결과에서 제외되는 효과 있음, 구체적인 구간은 [start_date, end_date) - - # 위와 같은 (end_date = start_date - 30 * krx_calendar.day) 코드는 거래소가 열리는 날짜 기준 30일 전 날짜 계산하는데 사용 - # 이렇게 설정해서 일봉데이터 가져올 경우 당일 포함되면 30일치, 당일 제외되면 29일치 가져오게 됨 - # 참고로 exchange_calendars 는 현재 년도의 말일까지 미리 계산된 휴일정보를 사용하므로 미래시간은 계산이 안됨 - - # 만약에 미래 시간에 대한 연산 또한 필요하다면 아래처럼 내부 구현체를 대체재로 사용해 볼 수 잇음 - # from koapy.utils.krx.calendar.KrxHolidayCalendar import KrxBusinessDay - # end_date = start_date + KrxBusinessDay(30) # (거래소 개장일 기준 30일 이후) - # 하지만 계산시 일반적인 휴일들을 제외한 임시공휴일, 선거일등은 별도 추가 데이터가 없는 한 반영되지 않으니 주의 - - # 일봉 데이터 - logging.info("Requesting daily data from %s to %s", end_date, start_date) - data = context.GetDailyStockDataAsDataFrame(code, start_date, end_date) - print(data) - - # 15분봉 데이터 - # 분봉과 틱봉은 TR 에서 기준날짜 (기간설정시 최근날짜) 지정이 안되므로 - # 가장 최근부터 가져오고 클라이언트에서 따로 추가로 거르는 식으로 구현되어 있음 - end_date = start_date - 1 * krx_calendar.day - logging.info("Requesting minute data from %s to %s", end_date, start_date) - data = context.GetMinuteStockDataAsDataFrame(code, 15, start_date, end_date) - print(data) - - # 주봉 데이터 - # 참고로 주봉은 각 주의 첫 개장일을 기준일으로 함 - end_date = start_date - 30 * krx_calendar.day - logging.info("Requesting weekly data from %s to %s", end_date, start_date) - data = context.GetWeeklyStockDataAsDataFrame(code, start_date, end_date) - print(data) - - # 월봉 데이터 - # 참고로 월봉은 각 달의 첫 개장일을 기준일으로 함 - end_date = start_date - 180 * krx_calendar.day - logging.info("Requesting monthly data from %s to %s", end_date, start_date) - data = context.GetMonthlyStockDataAsDataFrame(code, start_date, end_date) - print(data) - - # 30틱 데이터 - # 분봉과 틱봉은 TR 에서 기준날짜 (기간설정시 최근날짜) 지정이 안되므로 - # 가장 최근부터 가져오고 클라이언트에서 따로 추가로 거르는 식으로 구현되어 있음 - end_date = start_date - 1 * krx_calendar.day - logging.info("Requesting tick data from %s to %s", end_date, start_date) - data = context.GetTickStockDataAsDataFrame(code, 30, start_date, end_date) - print(data) diff --git a/koapy/examples/10_condition.py b/koapy/examples/10_condition.py deleted file mode 100644 index abc73bca..00000000 --- a/koapy/examples/10_condition.py +++ /dev/null @@ -1,62 +0,0 @@ -import threading - -import grpc - -from koapy import KiwoomOpenApiPlusEntrypoint - -with KiwoomOpenApiPlusEntrypoint() as context: - # 로그인 처리 - context.EnsureConnected() - - # 조건검색을 사용하기 위해서는 먼저 서버에 저장된 조건들을 불러와야함 (GetConditionLoad) - # 아래 함수는 조건을 불러온적이 없다면 불러오고 성공 이벤트까지 기다렸다 반환함 - # 이전 호출여부와 상관없이 강제로 다시 조건을 불러오려면 LoadCondition() 호출 - context.EnsureConditionLoaded() - - # 불러온 조건 리스트 확인, (조건번호, 조건이름) 쌍 리스트 반환 - conditions = context.GetConditionNameListAsList() - print(conditions) - - # 이후 예시의 정상동작을 위해 아래에서 사용되는 조건들과 같은 이름을 가지는 조건들이 미리 저장되어 있어야함 - # - 대형 저평가 우량주 - # - 중소형 저평가주 - - # 위의 조건식들은 키움에서 예시로 제공하는 추천식들을 그대로 이름을 똑같이 해서 저장한 것들임 - # 참고로 조건들을 편집하고 저장하는건 영웅문 HTS 내부에서만 가능함 - - # 조건검색을 실행할 첫 조건명 - condition_name = "대형 저평가 우량주" - - # 조건을 만족하는 코드 리스트를 바로 반환 (단순 조건검색) - codes, info = context.GetCodeListByCondition(condition_name, with_info=True) - print(codes) - print(info) - - # 조건검색을 다시 실행할 조건명 (같은 조건식은 1분에 1건 제한이므로 예시 실행시 제한을 회피하기 위해서 새로 설정) - condition_name = "중소형 저평가주" - - # 실시간 조건 검색 예시, 편입된/제외된 코드 리스트 쌍을 스트림으로 반환 (실시간 조건 검색) - stream = context.GetCodeListByConditionAsStream(condition_name) - - def stop_listening(): - print() - print("Stopping to listen events...") - stream.cancel() - - threading.Timer(10.0, stop_listening).start() # 10초 이후에 gRPC 커넥션 종료하도록 설정 - - # (디버깅을 위한) 이벤트 메시지 출력 함수 - from pprint import PrettyPrinter - - from google.protobuf.json_format import MessageToDict - - pp = PrettyPrinter() - - def pprint_event(event): - pp.pprint(MessageToDict(event, preserving_proto_field_name=True)) - - try: - for event in stream: - pprint_event(event) - except grpc.RpcError as e: - print(e) diff --git a/koapy/examples/11_compare_codes.py b/koapy/examples/11_compare_codes.py deleted file mode 100644 index f6a91f97..00000000 --- a/koapy/examples/11_compare_codes.py +++ /dev/null @@ -1,24 +0,0 @@ -import pandas as pd - -from koapy import CybosPlusEntrypoint, KiwoomOpenApiPlusEntrypoint - -kiwoom = KiwoomOpenApiPlusEntrypoint() -cybos = CybosPlusEntrypoint() - -kiwoom.EnsureConnected() -cybos.EnsureConnected() - -kiwoom_codes = kiwoom.GetGeneralCodeList() -cybos_codes = cybos.GetGeneralCodeList() - -cybos_codes = [code[1:] for code in cybos_codes] - -kiwoom_codes = pd.DataFrame(kiwoom_codes, columns=["code"]) -kiwoom_codes["kiwoom"] = "TRUE" - -cybos_codes = pd.DataFrame(cybos_codes, columns=["code"]) -cybos_codes["cybos"] = "TRUE" - -df = pd.merge(kiwoom_codes, cybos_codes, how="outer", on="code") - -df.to_excel("output.xlsx") diff --git a/koapy/examples/12_grpc_client_auth.py b/koapy/examples/12_grpc_client_auth.py deleted file mode 100644 index 7b8f7900..00000000 --- a/koapy/examples/12_grpc_client_auth.py +++ /dev/null @@ -1,27 +0,0 @@ -def main(): - import grpc - - from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient import ( - KiwoomOpenApiPlusServiceClient, - ) - - host = "localhost" - port = 5943 - - with open("server.crt", "rb") as f: - server_crt = f.read() - - credentials = grpc.ssl_channel_credentials( - root_certificates=server_crt, - private_key=None, - certificate_chain=None, - ) - - client = KiwoomOpenApiPlusServiceClient( - host=host, port=port, credentials=credentials - ) - client.EnsureConnected() - - -if __name__ == "__main__": - main() diff --git a/koapy/examples/12_grpc_server_auth.py b/koapy/examples/12_grpc_server_auth.py deleted file mode 100644 index d4baf62c..00000000 --- a/koapy/examples/12_grpc_server_auth.py +++ /dev/null @@ -1,78 +0,0 @@ -def generate_tls_certificate(ou, cn): - import random - - import OpenSSL - - cert_seconds_to_expiry = 60 * 60 * 24 * 365 # one year - - key = OpenSSL.crypto.PKey() - key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) - - cert = OpenSSL.crypto.X509() - cert.get_subject().OU = ou - cert.get_subject().CN = cn - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(cert_seconds_to_expiry) - cert.set_serial_number(random.getrandbits(64)) - cert.set_issuer(cert.get_subject()) - cert.set_pubkey(key) - cert.sign(key, "sha256") - - with open("server.key", "wb") as f: - f.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)) - with open("server.crt", "wb") as f: - f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)) - - -def main(): - import signal - import sys - - import grpc - - from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget import ( - KiwoomOpenApiPlusQAxWidget, - ) - from koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer import ( - KiwoomOpenApiPlusServiceServer, - ) - from koapy.compat.pyside2.QtWidgets import QApplication - - host = "localhost" - port = 5943 - - app = QApplication.instance() - - if not app: - app = QApplication(sys.argv) - - control = KiwoomOpenApiPlusQAxWidget() - - with open("server.key", "rb") as f: - server_key = f.read() - with open("server.crt", "rb") as f: - server_crt = f.read() - - private_key_certificate_chain_pairs = [ - (server_key, server_crt), - ] - credentials = grpc.ssl_server_credentials( - private_key_certificate_chain_pairs=private_key_certificate_chain_pairs, - root_certificates=None, - require_client_auth=False, - ) - - server = KiwoomOpenApiPlusServiceServer( - control, host=host, port=port, credentials=credentials - ) - - # for Ctrl+C to work - signal.signal(signal.SIGINT, signal.SIG_DFL) - - server.start() - app.exec_() - - -if __name__ == "__main__": - generate_tls_certificate("koapy", "localhost") - main() diff --git a/koapy/examples/__init__.py b/koapy/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/__init__.py b/koapy/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/builtin.py b/koapy/utils/builtin.py deleted file mode 100644 index 06ac2271..00000000 --- a/koapy/utils/builtin.py +++ /dev/null @@ -1,2 +0,0 @@ -def dir_public(*args): - return [name for name in dir(*args) if not name.startswith("_")] diff --git a/koapy/utils/ctypes.py b/koapy/utils/ctypes.py deleted file mode 100644 index ece04837..00000000 --- a/koapy/utils/ctypes.py +++ /dev/null @@ -1,5 +0,0 @@ -import ctypes - - -def is_admin(): - return ctypes.windll.shell32.IsUserAnAdmin() != 0 diff --git a/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.py b/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.py deleted file mode 100644 index 7defa309..00000000 --- a/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader.py +++ /dev/null @@ -1,160 +0,0 @@ -import pandas as pd -import requests - -from exchange_calendars import get_calendar - - -class KrxHistoricalDailyPriceDataDownloader: - def __init__(self): - self._headers = { - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "en-US,en;q=0.9,ko;q=0.8,fr;q=0.7,ja;q=0.6,zh-CN;q=0.5,zh;q=0.4", - "Host": "data.krx.co.kr", - "Origin": "http://data.krx.co.kr", - "Referer": "http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201020103", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", - "X-Requested-With": "XMLHttpRequest", - } - - self._stocks = None - self._stocks_delisted = None - - self._bld = "dbms/MDC/STAT/standard/MDCSTAT01701" - self._isuCd = "" - - self._calendar = get_calendar("XKRX") - self._start_date = self._calendar.first_session - - def get_stocks(self): - data = { - "mktsel": "ALL", - "typeNo": "0", - "searchText": "", - "bld": "dbms/comm/finder/finder_stkisu", - } - url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" - response = requests.post(url, data, headers=self._headers) - df = pd.json_normalize(response.json()["block1"]) - df = df.set_index("short_code") - return df - - def get_stocks_delisted(self): - data = { - "mktsel": "ALL", - "searchText": "", - "bld": "dbms/comm/finder/finder_listdelisu", - } - url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" - response = requests.post(url, data, headers=self._headers) - df = pd.json_normalize(response.json()["block1"]) - df = df.set_index("short_code") - return df - - @property - def stocks(self): - if self._stocks is None: - self._stocks = self.get_stocks() - return self._stocks - - @property - def stocks_delisted(self): - if self._stocks_delisted is None: - self._stocks_delisted = self.get_stocks_delisted() - return self._stocks_delisted - - def get_full_code(self, symbol): - if symbol in self.stocks.index: - return self.stocks.loc[symbol]["full_code"] - if symbol in self.stocks_delisted.index: - return self.stocks_delisted.loc[symbol]["full_code"] - raise ValueError("No full_code found for given symbol %s" % symbol) - - def get_name(self, symbol): - if symbol in self.stocks.index: - return self.stocks.loc[symbol]["codeName"] - if symbol in self.stocks_delisted.index: - return self.stocks_delisted.loc[symbol]["codeName"] - raise ValueError("No name found for given symbol %s" % symbol) - - def download(self, symbol, start_date=None, end_date=None): - if start_date is None: - start_date = self._start_date - if end_date is None: - now = pd.Timestamp.now(self._calendar.tz) - end_date = ( - self._calendar.previous_close(now) - .astimezone(self._calendar.tz) - .normalize() - ) - - full_code = self.get_full_code(symbol) - name = self.get_name(symbol) - - url = "http://data.krx.co.kr/comm/bldAttendant/getJsonData.cmd" - data = { - "bld": self._bld, - "tboxisuCd_finder_stkisu0_0": "{}/{}".format(symbol, name), - "isuCd": full_code, - "isuCd2": self._isuCd, - "codeNmisuCd_finder_stkisu0_0": name, - "param1isuCd_finder_stkisu0_0": "ALL", - "strtDd": start_date.strftime("%Y%m%d"), - "endDd": end_date.strftime("%Y%m%d"), - "share": "1", - "money": "1", - "csvxls_isNo": "false", - } - self._isuCd = full_code - - response = requests.post(url, data, headers=self._headers) - output = response.json()["output"] - - if len(output) == 0: - return None - - df = pd.json_normalize(output) - - column_names = { - "TRD_DD": "Date", - "ISU_CD": "Code", - "ISU_NM": "Name", - "MKT_NM": "Market", - "SECUGRP_NM": "SecuGroup", - "TDD_CLSPRC": "Close", - "FLUC_TP_CD": "UpDown", - "CMPPRVDD_PRC": "Change", - "FLUC_RT": "ChangeRate", - "TDD_OPNPRC": "Open", - "TDD_HGPRC": "High", - "TDD_LWPRC": "Low", - "ACC_TRDVOL": "Volume", - "ACC_TRDVAL": "Amount", - "MKTCAP": "MarCap", - "CMPPREVDD_PRC": "Change", - "LIST_SHRS": "Shares", - } - df.rename(columns=column_names, inplace=True) - - int_columns = [ - "Close", - "UpDown", - "Change", - "ChangeRate", - "Open", - "High", - "Low", - "Volume", - "Amount", - "MarCap", - "Shares", - ] - - for col in int_columns: - if col in df.columns: - df[col] = pd.to_numeric(df[col].str.replace(",", ""), errors="coerce") - - df["Date"] = pd.to_datetime(df["Date"]) - df.set_index("Date", inplace=True) - - return df diff --git a/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.py b/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.py deleted file mode 100644 index 676a49b9..00000000 --- a/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader.py +++ /dev/null @@ -1,135 +0,0 @@ -import numpy as np -import pandas as pd - -from exchange_calendars import get_calendar -from tqdm import tqdm - -from ..store import SQLiteStore -from .KrxHistoricalDailyPriceDataLoader import KrxHistoricalDailyPriceDataLoader - - -class KrxHistoricalDailyPriceDataForBacktestLoader: - def __init__(self, filename, library=None): - self._loader = KrxHistoricalDailyPriceDataLoader(filename) - self._store = SQLiteStore(filename) - self._calendar = get_calendar("XKRX") - - if library is None: - library = "XKRX-ALL-BACKTEST" - - self._library = self._store.get_or_create_library(library) - - @classmethod - def get_adjust_ratios(cls, data, sort=True): - if sort: - data = data.sort_index(ascending=False) - adjust_ratios = [] - last_close = data["Close"].iloc[0] - last_adjust_ratio = 1.0 - adjust_ratios.append(last_adjust_ratio) - eleven_days = pd.Timedelta(11, unit="D") - for i in range(data.shape[0] - 1): - if data.index[i] - data.index[i + 1] > eleven_days: - last_close = data["Close"].iloc[i + 1] - last_adjust_ratio = 1.0 - else: - last_close = last_close - data["Change"].iloc[i] * last_adjust_ratio - last_adjust_ratio = last_close / data["Close"].iloc[i + 1] - adjust_ratios.append(last_adjust_ratio) - adjust_ratios = np.array(adjust_ratios) - return adjust_ratios - - @classmethod - def adjust_data(cls, data, sort=True): - if sort: - data = data.sort_index(ascending=False) - adjust_ratios = cls.get_adjust_ratios(data, sort=False) - data["Open"] = data["Open"] * adjust_ratios - data["High"] = data["High"] * adjust_ratios - data["Low"] = data["Low"] * adjust_ratios - data["Close"] = data["Close"] * adjust_ratios - data["Volume"] = data["Volume"] / adjust_ratios - return data - - def get_symbols(self): - return self._library.list_symbols() - - def update(self, download=False, progress_bar=False): - now = pd.Timestamp.now(self._calendar.tz) - end_date = ( - self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize() - ) - - symbols_with_delisted = {} - - for symbol in self._loader.symbols: - symbols_with_delisted.setdefault(symbol, False) - for symbol in self._loader.symbols_delisted: - symbols_with_delisted.setdefault(symbol, True) - - entire_index = pd.DatetimeIndex([], name="Date") - - entire_data = {} - entire_data_converted = {} - - progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar) - for symbol, is_delisted in progress: - progress.set_description("Loading Symbol [%s]" % symbol) - if download: - versioned_item = self._loader.load_or_download( - symbol, is_delisted=is_delisted, end_date=end_date - ) - else: - versioned_item = self._loader.load_from_database( - symbol, is_delisted=is_delisted - ) - if versioned_item is not None: - entire_data[symbol] = versioned_item.data - - progress = tqdm(entire_data.items(), disable=not progress_bar) - for symbol, data in progress: - progress.set_description("Adjusting Symbol [%s]" % symbol) - entire_index = entire_index.union(data.index) - data = data[data["Close"] > 0] - if data.shape[0] > 0: - data = self.adjust_data(data) - data = data.sort_index() - columns = [ - "Open", - "High", - "Low", - "Close", - "Volume", - "Amount", - "MarCap", - "Shares", - ] - data = data[columns] - entire_data_converted[symbol] = data - - progress = tqdm(entire_data_converted.items(), disable=not progress_bar) - for symbol, data in progress: - progress.set_description("Saving Symbol [%s]" % symbol) - data = data.reindex(entire_index) - data = data.fillna(0) - self._library.write(symbol, data) - - def load(self, symbol, start_time=None, end_time=None): - if self._library.has_symbol(symbol): - versioned_item = self._library.read( - symbol, start_time=start_time, end_time=end_time - ) - if ( - versioned_item is not None - and versioned_item.data is not None - and versioned_item.data.shape[0] > 0 - ): - return versioned_item.data - - def load_as_cursor(self, symbol, start_time=None, end_time=None): - if self._library.has_symbol(symbol): - versioned_item = self._library.read_as_cursor( - symbol, start_time=start_time, end_time=end_time - ) - if versioned_item is not None and versioned_item.data is not None: - return versioned_item.data diff --git a/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.py b/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.py deleted file mode 100644 index d7284893..00000000 --- a/koapy/utils/data/KrxHistoricalDailyPriceDataLoader.py +++ /dev/null @@ -1,121 +0,0 @@ -import pandas as pd - -from exchange_calendars import get_calendar -from tqdm import tqdm - -from ..store import SQLiteStore -from .KrxHistoricalDailyPriceDataDownloader import KrxHistoricalDailyPriceDataDownloader - - -class KrxHistoricalDailyPriceDataLoader: - def __init__(self, filename, library=None, library_delisted=None): - self._downloader = KrxHistoricalDailyPriceDataDownloader() - self._store = SQLiteStore(filename) - self._calendar = get_calendar("XKRX") - - if library is None: - library = "XKRX" - if library_delisted is None: - library_delisted = "XKRX-DELISTED" - - self._library = self._store.get_or_create_library(library) - self._library_delisted = self._store.get_or_create_library(library_delisted) - - @property - def symbols(self): - return self._downloader.stocks.index - - @property - def symbols_delisted(self): - return self._downloader.stocks_delisted.index - - def load_from_database(self, symbol, is_delisted=None): - if is_delisted is None: - is_delisted = symbol not in self.symbols - - library = self._library if not is_delisted else self._library_delisted - - if library.has_symbol(symbol): - versioned_item = library.read(symbol) - if versioned_item.data is not None and versioned_item.data.shape[0] > 0: - return versioned_item - - def load_or_download( - self, symbol, is_delisted=None, start_date=None, end_date=None - ): - if is_delisted is None: - is_delisted = symbol not in self.symbols - - library = self._library - now = pd.Timestamp.now(self._calendar.tz) - - if is_delisted: - library = self._library_delisted - - if library.has_symbol(symbol): - versioned_item = self.load_from_database(symbol, is_delisted=is_delisted) - if not is_delisted and versioned_item is not None: - if start_date is None: - start_date = ( - versioned_item.data.index.max().tz_localize(self._calendar.tz) - + self._calendar.day - ) - if end_date is None: - end_date = ( - self._calendar.previous_close(now) - .astimezone(self._calendar.tz) - .normalize() - ) - if start_date <= end_date: - recent_data = self._downloader.download( - symbol, start_date=start_date - ) - if recent_data is not None and recent_data.shape[0] > 0: - data = versioned_item.data - data = data.combine_first(recent_data)[data.columns] - data = data.convert_dtypes(convert_floating=False) - data = data.sort_index() - versioned_item = library.write(symbol, data) - return versioned_item - else: - data = self._downloader.download( - symbol, start_date=start_date, end_date=end_date - ) - if data is not None and data.shape[0] > 0: - data = data.convert_dtypes(convert_floating=False) - data = data.sort_index() - versioned_item = library.write(symbol, data) - return versioned_item - - def load( - self, symbol, is_delisted=None, start_date=None, end_date=None, download=True - ): - if download: - return self.load_or_download( - symbol, - is_delisted=is_delisted, - start_date=start_date, - end_date=end_date, - ) - else: - return self.load_from_database(symbol, is_delisted=is_delisted) - - def update(self, progress_bar=False): - now = pd.Timestamp.now(self._calendar.tz) - end_date = ( - self._calendar.previous_close(now).astimezone(self._calendar.tz).normalize() - ) - - symbols_with_delisted = {} - - for symbol in self.symbols: - symbols_with_delisted.setdefault(symbol, False) - for symbol in self.symbols_delisted: - symbols_with_delisted.setdefault(symbol, True) - - progress = tqdm(symbols_with_delisted.items(), disable=not progress_bar) - for symbol, is_delisted in progress: - progress.set_description("Updating Symbol [%s]" % symbol) - _versioned_item = self.load_or_download( - symbol, is_delisted=is_delisted, end_date=end_date - ) diff --git a/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.py b/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.py deleted file mode 100644 index 96f89568..00000000 --- a/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader.py +++ /dev/null @@ -1,39 +0,0 @@ -import io - -import pandas as pd -import requests - - -class YahooFinanceKrxHistoricalDailyPriceDataDownloader: - def __init__(self): - self._headers = { - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36", - } - - def download(self, symbol, start_date=None, end_date=None): - if start_date is None: - start_date = pd.Timestamp(1980, 1, 1) - elif not isinstance(start_date, pd.Timestamp): - start_date = pd.Timestamp(start_date) - if end_date is None: - end_date = pd.Timestamp.now().normalize() + pd.Timedelta(1, unit="day") - elif not isinstance(end_date, pd.Timestamp): - end_date = pd.Timestamp(end_date) - - url = ( - "https://query1.finance.yahoo.com/v7/finance/download/%s.KS" - % symbol.upper() - ) - params = { - "period1": int(start_date.timestamp()), - "period2": int(end_date.timestamp()), - "interval": "1d", - "events": "history", - "includeAdjustedClose": "true", - } - response = requests.get(url, params=params, headers=self._headers) - df = pd.read_csv( - io.BytesIO(response.content), parse_dates=["Date"], index_col="Date" - ) - - return df diff --git a/koapy/utils/data/__init__.py b/koapy/utils/data/__init__.py deleted file mode 100644 index bea2aab5..00000000 --- a/koapy/utils/data/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .KrxHistoricalDailyPriceDataDownloader import KrxHistoricalDailyPriceDataDownloader -from .KrxHistoricalDailyPriceDataForBacktestLoader import ( - KrxHistoricalDailyPriceDataForBacktestLoader, -) -from .KrxHistoricalDailyPriceDataLoader import KrxHistoricalDailyPriceDataLoader diff --git a/koapy/utils/datetime.py b/koapy/utils/datetime.py deleted file mode 100644 index 09f554ac..00000000 --- a/koapy/utils/datetime.py +++ /dev/null @@ -1,10 +0,0 @@ -def is_naive(dt): - return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None - - -def localize(dt, tz): - if is_naive(dt): - dt = tz.localize(dt) - else: - dt = dt.astimezone(tz) - return dt diff --git a/koapy/utils/exchange_calendars.py b/koapy/utils/exchange_calendars.py deleted file mode 100644 index 326898e3..00000000 --- a/koapy/utils/exchange_calendars.py +++ /dev/null @@ -1,20 +0,0 @@ -from exchange_calendars import get_calendar -from pandas import Timestamp - -name = "XKRX" -calendar = get_calendar(name) -day = calendar.day - - -def is_currently_in_session() -> bool: - now = Timestamp.now(calendar.tz).floor("T") - previous_open = calendar.previous_open(now).astimezone(calendar.tz) - next_close = calendar.next_close(previous_open).astimezone(calendar.tz) - return previous_open <= now <= next_close - - -def get_last_session_date() -> Timestamp: - now = Timestamp.now(calendar.tz).floor("T") - previous_close = calendar.previous_close(now).astimezone(calendar.tz) - previous_open = calendar.previous_open(previous_close).astimezone(calendar.tz) - return previous_open.normalize() diff --git a/koapy/utils/grpc.py b/koapy/utils/grpc.py deleted file mode 100644 index 4fc356fb..00000000 --- a/koapy/utils/grpc.py +++ /dev/null @@ -1,34 +0,0 @@ -import contextlib -import threading -import warnings - -from pprint import PrettyPrinter - -import grpc - -from google.protobuf.json_format import MessageToDict - - -@contextlib.contextmanager -def warn_on_rpc_error_context(): - try: - yield - except grpc.RpcError as e: - warnings.warn(str(e)) - - -def warn_on_rpc_error(stream): - with warn_on_rpc_error_context(): - for event in stream: - yield event - - -def cancel_after(stream, after): - timer = threading.Timer(after, stream.cancel) - timer.start() - return warn_on_rpc_error(stream) - - -def pprint_message(message): - pp = PrettyPrinter() - pp.pprint(MessageToDict(message, preserving_proto_field_name=True)) diff --git a/koapy/utils/itertools.py b/koapy/utils/itertools.py deleted file mode 100644 index 2b72b626..00000000 --- a/koapy/utils/itertools.py +++ /dev/null @@ -1,9 +0,0 @@ -import itertools - - -def chunk(iterable, n): - fillvalue = object() - args = [iter(iterable)] * n - it = itertools.zip_longest(fillvalue=fillvalue, *args) - it = map(lambda items: [item for item in items if item is not fillvalue], it) - return it diff --git a/koapy/utils/logging/Logging.py b/koapy/utils/logging/Logging.py deleted file mode 100644 index 59b0614a..00000000 --- a/koapy/utils/logging/Logging.py +++ /dev/null @@ -1,151 +0,0 @@ -import inspect -import logging -import logging.config -import threading - - -class LoggingMeta(type): - - __default_config = { - "version": 1, - "formatters": { - "default": { - "format": "%(asctime)s [%(levelname)s] %(message)s - %(filename)s:%(lineno)d", - }, - }, - "handlers": { - "console": { - "class": "logging.StreamHandler", - "level": "NOTSET", - "formatter": "default", - }, - }, - "loggers": { - "koapy": { - "level": "DEBUG", - "propagate": False, - "handlers": ["console"], - }, - }, - "incremental": False, - "disable_existing_loggers": False, - } - - __config_key = "koapy.utils.logging.config" - - __initialized = False - __init_lock = threading.RLock() - - def __initialize_if_necessary(cls): - if not LoggingMeta.__initialized: - with LoggingMeta.__init_lock: - if not LoggingMeta.__initialized: - LoggingMeta.__initialize(cls) - - def __initialize(cls): - from koapy.config import config - - logging_config_dict = config.get( - LoggingMeta.__config_key, LoggingMeta.__default_config - ) - - logging.basicConfig() - logging.config.dictConfig(logging_config_dict) - LoggingMeta.__initialized = True - - def __new__(cls, clsname, bases, dct): - return super().__new__(cls, clsname, bases, dct) - - def __init__(cls, clsname, bases, dct): - super().__init__(clsname, bases, dct) - cls.__logger = None - - def get_logger(cls, name=None): - LoggingMeta.__initialize_if_necessary(cls) - logger = logging.getLogger(name) - return logger - - def __module_name(cls): - module = inspect.getmodule(cls) - module_name = module.__spec__ and module.__spec__.name or module.__name__ - return module_name - - def __class_name(cls): - class_name = cls.__name__ - if hasattr(cls, "__outer_class__"): - class_name = "{}.{}".format( - LoggingMeta.__class_name(cls.__outer_class__), - class_name, - ) - return class_name - - def __logger_name(cls): - module_name = LoggingMeta.__module_name(cls) - class_name = LoggingMeta.__class_name(cls) - logger_name = "{}.{}".format(module_name, class_name) - return logger_name - - def get_class_logger(cls): - name = LoggingMeta.__logger_name(cls) - logger = LoggingMeta.get_logger(cls, name) - return logger - - def get_module_logger(cls): - name = LoggingMeta.__module_name(cls) - logger = LoggingMeta.get_logger(cls, name) - return logger - - def get_package_logger(cls): - name = LoggingMeta.__module_name(cls) - name = name.split(".", maxsplit=1)[0] - logger = LoggingMeta.get_logger(cls, name) - return logger - - def _logger(cls): - if cls.__logger is None: - cls.__logger = LoggingMeta.get_class_logger(cls) - return cls.__logger - - @property - def logger(cls): - return LoggingMeta._logger(cls) - - def verbosity_to_loglevel(cls, verbosity): - verbosity = verbosity or 0 - levels = [ - logging.WARNING, - logging.INFO, - logging.DEBUG, - ] - if verbosity >= len(levels): - verbosity = -1 - level = levels[verbosity] - return level - - def loglevel_to_verbosity(cls, loglevel): - verbosity = 3 - (loglevel + 9) // 10 - if verbosity < 0: - verbosity = 0 - return verbosity - - def set_loglevel(cls, loglevel=logging.WARNING): - return LoggingMeta._logger(cls).setLevel(loglevel) - - def set_verbosity(cls, verbosity=0): - loglevel = LoggingMeta.verbosity_to_loglevel(cls, verbosity) - LoggingMeta.set_loglevel(cls, loglevel) - return loglevel - - def get_loglevel(cls): - return LoggingMeta._logger(cls).level - - def get_verbosity(cls): - loglevel = LoggingMeta.get_loglevel(cls) - verbosity = LoggingMeta.loglevel_to_verbosity(cls, loglevel) - return verbosity - - -class Logging(metaclass=LoggingMeta): - @property - def logger(self): - return type(self)._logger() diff --git a/koapy/utils/logging/__init__.py b/koapy/utils/logging/__init__.py deleted file mode 100644 index a901f70d..00000000 --- a/koapy/utils/logging/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -from .Logging import Logging - - -def get_logger(name=None): - return Logging.get_logger(name) - - -def verbosity_to_loglevel(verbosity): - return Logging.verbosity_to_loglevel(verbosity) - - -def loglevel_to_verbosity(loglevel): - return Logging.loglevel_to_verbosity(loglevel) - - -def get_package_logger(): - root_package_name = __name__.split(".", maxsplit=1)[0] - logger = get_logger(root_package_name) - return logger - - -def set_loglevel(loglevel): - logger = get_package_logger() - logger.setLevel(loglevel) - - -def set_verbosity(verbosity): - loglevel = verbosity_to_loglevel(verbosity) - set_loglevel(loglevel) - - -def get_loglevel(): - logger = get_package_logger() - loglevel = logger.level - return loglevel - - -def get_verbosity(): - loglevel = get_loglevel() - verbosity = loglevel_to_verbosity(loglevel) - return verbosity diff --git a/koapy/utils/logging/pyside2/QAbstractSocketLogging.py b/koapy/utils/logging/pyside2/QAbstractSocketLogging.py deleted file mode 100644 index aeb21c78..00000000 --- a/koapy/utils/logging/pyside2/QAbstractSocketLogging.py +++ /dev/null @@ -1,14 +0,0 @@ -from koapy.compat.pyside2.QtNetwork import QAbstractSocket -from koapy.utils.logging.Logging import Logging - - -class QAbstractSocketLoggingMeta(type(Logging), type(QAbstractSocket)): - pass - - -class QAbstractSocketLogging( - QAbstractSocket, Logging, metaclass=QAbstractSocketLoggingMeta -): - def __init__(self, *args, **kwargs): - QAbstractSocket.__init__(self, *args, **kwargs) - Logging.__init__(self) diff --git a/koapy/utils/logging/pyside2/QObjectLogging.py b/koapy/utils/logging/pyside2/QObjectLogging.py deleted file mode 100644 index 574ff347..00000000 --- a/koapy/utils/logging/pyside2/QObjectLogging.py +++ /dev/null @@ -1,12 +0,0 @@ -from koapy.compat.pyside2.QtCore import QObject -from koapy.utils.logging.Logging import Logging - - -class QObjectLoggingMeta(type(Logging), type(QObject)): - pass - - -class QObjectLogging(QObject, Logging, metaclass=QObjectLoggingMeta): - def __init__(self, *args, **kwargs): - QObject.__init__(self, *args, **kwargs) - Logging.__init__(self) diff --git a/koapy/utils/logging/pyside2/QThreadLogging.py b/koapy/utils/logging/pyside2/QThreadLogging.py deleted file mode 100644 index 1c03d3e2..00000000 --- a/koapy/utils/logging/pyside2/QThreadLogging.py +++ /dev/null @@ -1,12 +0,0 @@ -from koapy.compat.pyside2.QtCore import QThread -from koapy.utils.logging.Logging import Logging - - -class QThreadLoggingMeta(type(Logging), type(QThread)): - pass - - -class QThreadLogging(QThread, Logging, metaclass=QThreadLoggingMeta): - def __init__(self, *args, **kwargs): - QThread.__init__(self, *args, **kwargs) - Logging.__init__(self) diff --git a/koapy/utils/logging/pyside2/QWidgetLogging.py b/koapy/utils/logging/pyside2/QWidgetLogging.py deleted file mode 100644 index 96304a44..00000000 --- a/koapy/utils/logging/pyside2/QWidgetLogging.py +++ /dev/null @@ -1,12 +0,0 @@ -from koapy.compat.pyside2.QtWidgets import QWidget -from koapy.utils.logging.Logging import Logging - - -class QWidgetLoggingMeta(type(Logging), type(QWidget)): - pass - - -class QWidgetLogging(QWidget, Logging, metaclass=QWidgetLoggingMeta): - def __init__(self, *args, **kwargs): - QWidget.__init__(self, *args, **kwargs) - Logging.__init__(self) diff --git a/koapy/utils/logging/pyside2/__init__.py b/koapy/utils/logging/pyside2/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/logging/tqdm/TqdmStreamHandler.py b/koapy/utils/logging/tqdm/TqdmStreamHandler.py deleted file mode 100644 index 76ecb73b..00000000 --- a/koapy/utils/logging/tqdm/TqdmStreamHandler.py +++ /dev/null @@ -1,13 +0,0 @@ -import sys - -from logging import StreamHandler - -from tqdm.contrib import DummyTqdmFile - - -class TqdmStreamHandler(StreamHandler): - def __init__(self, stream=None): - if stream is None: - stream = sys.stderr - stream = DummyTqdmFile(stream) - StreamHandler.__init__(self, stream) diff --git a/koapy/utils/logging/tqdm/__init__.py b/koapy/utils/logging/tqdm/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/messaging/DiscordMessenger.py b/koapy/utils/messaging/DiscordMessenger.py deleted file mode 100644 index 20ddf526..00000000 --- a/koapy/utils/messaging/DiscordMessenger.py +++ /dev/null @@ -1,41 +0,0 @@ -import json - -import requests - -from discord import RequestsWebhookAdapter, Webhook - -from koapy.config import config -from koapy.utils.messaging.Messenger import Messenger - - -class DiscordWebhookMessenger(Messenger): - def __init__(self, url=None): - self._url = url or config.get_string( - "koapy.utils.messaging.discord.webhook_url" - ) - assert self._url is not None and len(self._url) > 0 - self._webhook = Webhook.from_url(self._url, adapter=RequestsWebhookAdapter()) - - def send_message(self, content): - return self._webhook.send(content) - - -class DoItYourselfDiscordWebhookMessenger(Messenger): - def __init__(self, url=None): - self._url = url or config.get_string( - "koapy.utils.messaging.discord.webhook_url" - ) - assert self._url is not None and len(self._url) > 0 - - def send_message(self, content): - headers = { - "Content-Type": "application/json", - } - data = { - "content": content, - } - data = json.dumps(data) - response = requests.post( - self._url, headers=headers, data=data, params={"wait": "true"} - ) - return response diff --git a/koapy/utils/messaging/Messenger.py b/koapy/utils/messaging/Messenger.py deleted file mode 100644 index b4c95036..00000000 --- a/koapy/utils/messaging/Messenger.py +++ /dev/null @@ -1,9 +0,0 @@ -from abc import ABC, abstractmethod - - -class Messenger(ABC): - """ """ - - @abstractmethod - def send_message(self, content): - raise NotImplementedError diff --git a/koapy/utils/messaging/__init__.py b/koapy/utils/messaging/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/networking.py b/koapy/utils/networking.py deleted file mode 100644 index ee69bcc0..00000000 --- a/koapy/utils/networking.py +++ /dev/null @@ -1,35 +0,0 @@ -import ipaddress -import socket - -from contextlib import closing - -from wrapt import synchronized - - -@synchronized -def find_free_port_for_host(host): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - with closing(sock) as sock: - sock.bind((host, 0)) - host, port = sock.getsockname() - return port - - -def get_free_localhost_port(): - return find_free_port_for_host("localhost") - - -def is_in_private_network(host): - host = socket.gethostbyname(host) - ip_address = ipaddress.ip_address(host) - private_networks = [ - "10.0.0.0/8", - "127.0.0.0/8", - "172.16.0.0/12", - "192.168.0.0/16", - ] - private_networks = [ipaddress.ip_network(network) for network in private_networks] - for private_network in private_networks: - if ip_address in private_network: - return True - return False diff --git a/koapy/utils/notimplemented.py b/koapy/utils/notimplemented.py deleted file mode 100644 index fce26e3a..00000000 --- a/koapy/utils/notimplemented.py +++ /dev/null @@ -1,11 +0,0 @@ -def notimplemented(func): - func.__isnotimplemented__ = True - return func - - -def isnotimplemented(func): - return getattr(func, "__isnotimplemented__", False) - - -def isimplemented(func): - return not isnotimplemented(func) diff --git a/koapy/utils/platform.py b/koapy/utils/platform.py deleted file mode 100644 index ae40bc2a..00000000 --- a/koapy/utils/platform.py +++ /dev/null @@ -1,14 +0,0 @@ -import platform -import sys - - -def is_windows(): - return sys.platform == "win32" - - -def is_32bit(): - return platform.architecture()[0] == "32bit" - - -def is_64bit(): - return platform.architecture()[0] == "64bit" diff --git a/koapy/utils/pywin32.py b/koapy/utils/pywin32.py deleted file mode 100644 index 2258a1ea..00000000 --- a/koapy/utils/pywin32.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import Dict, List, Optional, Sequence, Tuple, Union - -try: - from typing import TypeGuard -except ImportError: - from typing_extensions import TypeGuard - -from pythoncom import LoadRegTypeLib -from pythoncom import LoadTypeLib as LoadTypeLibFromDLL -from pywintypes import IIDType -from win32api import ( - ExpandEnvironmentStrings, - RegOpenKey, - RegQueryValue, - RegQueryValueEx, -) -from win32api import error as Win32ApiError -from win32com.client.genpy import ( - DispatchItem, - EnumerationItem, - Generator, - RecordItem, - VTableItem, -) -from win32com.client.selecttlb import EnumKeys, TypelibSpec -from win32con import HKEY_CLASSES_ROOT, REG_EXPAND_SZ - -PyIID = IIDType -PyITypeLib = "PyITypeLib" - -PyIIDLike = Union[PyIID, str] - - -def IsPyIID(value) -> TypeGuard[PyIID]: - return isinstance(value, IIDType) - - -def IsPyITypeLib(value) -> TypeGuard[PyITypeLib]: - return type(value).__name__ == PyITypeLib - - -def IsPyIIDLike(value) -> TypeGuard[PyIIDLike]: - return IsPyIID(value) or isinstance(value, str) - - -def GetTypelibSpecs(iid: PyIIDLike) -> List[TypelibSpec]: - specs: List[TypelibSpec] = [] - - try: - key = RegOpenKey(HKEY_CLASSES_ROOT, "TypeLib") - key2 = RegOpenKey(key, str(iid)) - except Win32ApiError: - enum_keys = [] - else: - enum_keys = EnumKeys(key2) - - for version, tlbdesc in enum_keys: - major_minor = version.split(".", 1) - if len(major_minor) < 2: - major_minor.append("0") - major = major_minor[0] - minor = major_minor[1] - key3 = RegOpenKey(key2, str(version)) - try: - flags = int(RegQueryValue(key3, "FLAGS")) - except (Win32ApiError, ValueError): - flags = 0 - for lcid, _ in EnumKeys(key3): - try: - lcid = int(lcid) - except ValueError: - continue - try: - key4 = RegOpenKey(key3, f"{lcid}\\win32") - except Win32ApiError: - try: - key4 = RegOpenKey(key3, f"{lcid}\\win64") - except Win32ApiError: - continue - try: - dll, typ = RegQueryValueEx(key4, None) - if typ == REG_EXPAND_SZ: - dll = ExpandEnvironmentStrings(dll) - except Win32ApiError: - dll = None - spec = TypelibSpec(iid, lcid, major, minor, flags) - spec.dll = dll - spec.desc = tlbdesc - spec.ver_desc = tlbdesc + " (" + version + ")" - specs.append(spec) - - return specs - - -def GetLatestTypelibSpec( - specs: Union[Sequence[TypelibSpec], PyIIDLike] -) -> Optional[TypelibSpec]: - spec: Optional[TypelibSpec] = None - - if IsPyIIDLike(specs): - specs = GetTypelibSpecs(specs) - - if len(specs) > 0: - specs = sorted(specs) - spec = specs[-1] - - return spec - - -def LoadTypeLib(spec: Union[TypelibSpec, PyIIDLike]) -> Optional[PyITypeLib]: - tlb: Optional[PyITypeLib] = None - - if IsPyIIDLike(spec): - spec = GetLatestTypelibSpec(spec) - - if spec: - if spec.dll: - tlb = LoadTypeLibFromDLL(spec.dll) - else: - tlb = LoadRegTypeLib( - spec.clsid, - spec.major, - spec.minor, - spec.lcid, - ) - - return tlb - - -def BuildOleItems( - spec: Union[TypelibSpec, PyIIDLike], - tlb: Optional[PyITypeLib] = None, -) -> Tuple[ - Dict[PyIID, DispatchItem], - Dict[PyIID, EnumerationItem], - Dict[PyIID, RecordItem], - Dict[PyIID, VTableItem], -]: - ole_items: Dict[PyIID, DispatchItem] = {} - enum_items: Dict[PyIID, EnumerationItem] = {} - record_items: Dict[PyIID, RecordItem] = {} - vtable_items: Dict[PyIID, VTableItem] = {} - - if IsPyIIDLike(spec): - spec = GetLatestTypelibSpec(spec) - - if spec: - if not tlb: - tlb = LoadTypeLib(spec) - progress_instance = None - gen = Generator(tlb, spec.dll, progress_instance, bBuildHidden=1) - ole_items, enum_items, record_items, vtable_items = gen.BuildOleItemsFromType() - - return ole_items, enum_items, record_items, vtable_items diff --git a/koapy/utils/pywinauto.py b/koapy/utils/pywinauto.py deleted file mode 100644 index d1a7d5af..00000000 --- a/koapy/utils/pywinauto.py +++ /dev/null @@ -1,31 +0,0 @@ -import time - -from typing import Callable, Optional, Sequence, TypeVar - -T = TypeVar("T") - - -def wait_any( - waits: Sequence[Callable[[], T]], - timeout: Optional[int] = None, - retry_interval: Optional[int] = None, -) -> T: - import pywinauto.timings - - if timeout is None: - timeout = pywinauto.timings.Timings.window_find_timeout - if retry_interval is None: - retry_interval = pywinauto.timings.Timings.window_find_retry - - start_time = time.time() - should_stop = False - - while not should_stop: - for wait in waits: - try: - return wait() - except pywinauto.timings.TimeoutError: - elapsed_seconds = time.time() - start_time - if elapsed_seconds > timeout: - raise - time.sleep(retry_interval) diff --git a/koapy/utils/rate_limiting/RateLimiter.py b/koapy/utils/rate_limiting/RateLimiter.py deleted file mode 100644 index 087c7287..00000000 --- a/koapy/utils/rate_limiting/RateLimiter.py +++ /dev/null @@ -1,80 +0,0 @@ -import collections -import threading -import time - -from typing import List - -from koapy.utils.logging.Logging import Logging - - -class RateLimiter: - def check_sleep_seconds(self, *args, **kwargs): - return 0 - - def add_call_history(self, *args, **kwargs): - pass - - def sleep_if_necessary(self, *args, **kwargs): - sleep_seconds = self.check_sleep_seconds(*args, **kwargs) - if sleep_seconds > 0: - time.sleep(sleep_seconds) - - -class TimeWindowRateLimiter(RateLimiter, Logging): - def __init__(self, period, calls): - super().__init__() - - self._period = period - self._calls = calls - - self._lock = threading.RLock() - self._clock = time.time - - if hasattr(time, "monotonic"): - self._clock = time.monotonic - - self._call_history = collections.deque(maxlen=self._calls) - - def check_sleep_seconds(self, *args, **kwargs): - with self._lock: - if len(self._call_history) < self._calls: - return 0 - clock = self._clock() - remaining = self._call_history[0] + self._period - clock - return remaining - - def add_call_history(self, *args, **kwargs): - with self._lock: - return self._call_history.append(self._clock()) - - def sleep_if_necessary(self, *args, **kwargs): - with self._lock: - sleep_seconds = self.check_sleep_seconds(*args, **kwargs) - if sleep_seconds > 0: - time.sleep(sleep_seconds) - - -class CompositeTimeWindowRateLimiter(RateLimiter): - def __init__(self, limiters: List[RateLimiter]): - super().__init__() - - self._lock = threading.RLock() - self._limiters = limiters - - def check_sleep_seconds(self, *args, **kwargs): - with self._lock: - return max( - limiter.check_sleep_seconds(*args, **kwargs) - for limiter in self._limiters - ) - - def add_call_history(self, *args, **kwargs): - with self._lock: - for limiter in self._limiters: - limiter.add_call_history(*args, **kwargs) - - def sleep_if_necessary(self, *args, **kwargs): - with self._lock: - sleep_seconds = self.check_sleep_seconds(*args, **kwargs) - if sleep_seconds > 0: - time.sleep(sleep_seconds) diff --git a/koapy/utils/rate_limiting/__init__.py b/koapy/utils/rate_limiting/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/recursion.py b/koapy/utils/recursion.py deleted file mode 100644 index 17bb6812..00000000 --- a/koapy/utils/recursion.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -""" - -""" -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to -""" - -# https://github.com/andrewp-as-is/recursion-detect.py - -import inspect - - -def depth(): - """return recursion depth. 0 if no recursion""" - counter = 0 - frames = inspect.getouterframes(inspect.currentframe())[1:] - top_frame = inspect.getframeinfo(frames[0][0]) - for frame, _, _, _, _, _ in frames[1:]: - (path, line_number, func_name, lines, index) = inspect.getframeinfo(frame) - if path == top_frame[0] and func_name == top_frame[2]: - counter += 1 - return counter - - -__all__ = ["depth"] diff --git a/koapy/utils/serialization.py b/koapy/utils/serialization.py deleted file mode 100644 index 03957012..00000000 --- a/koapy/utils/serialization.py +++ /dev/null @@ -1,42 +0,0 @@ -import io -import json -import os - - -class JsonSerializable: - def to_dict(self): - return dict(self.__dict__) - - @classmethod - def from_dict(cls, dic): - output = cls() - for name in output.__dict__: - setattr(output, name, dic.get(name)) - return output - - def to_json(self, f=None, encoding=None): - if f is None: - return json.dumps(self.to_dict()) - elif isinstance(f, str): - with open(f, "w", encoding=encoding) as f: - return json.dump(self.to_dict(), f) - elif isinstance(f, io.TextIOBase): - return json.dump(self.to_dict(), f) - else: - raise ValueError("Unsupported argument type: %s" % type(f)) - - @classmethod - def from_json(cls, jsn, encoding=None): - if isinstance(jsn, str): - if jsn.startswith("{") and jsn.endswith("}"): - dic = json.loads(jsn) - elif os.path.exists(jsn): - with open(jsn, "r", encoding=encoding) as f: - dic = json.load(f) - else: - dic = json.loads(jsn) - elif isinstance(jsn, io.TextIOBase): - dic = json.load(jsn) - else: - raise ValueError("Unsupported argument type: %s" % type(jsn)) - return cls.from_dict(dic) diff --git a/koapy/utils/store/SQLiteFileLibrary.py b/koapy/utils/store/SQLiteFileLibrary.py deleted file mode 100644 index 6fb3d3e9..00000000 --- a/koapy/utils/store/SQLiteFileLibrary.py +++ /dev/null @@ -1,141 +0,0 @@ -import pandas as pd -import pytz - -from sqlalchemy import create_engine, inspect, select -from sqlalchemy.schema import DropTable, MetaData, Table - -from .sqlalchemy.Timestamp import Timestamp - - -class SQLiteFileLibrary: - def __init__(self, filename): - self._engine = create_engine("sqlite:///" + filename) - self._inspector = inspect(self._engine) - - def list_symbols(self): - return self._inspector.get_table_names() - - def has_symbol(self, symbol): - return self._inspector.has_table(symbol) - - def write(self, symbol, data): - index_original_names = [name for name in data.index.names] - index_table_names = [ - name if name is not None else "index_%d" % i - for i, name in enumerate(data.index.names) - ] - - datetime_columns = [ - (name, dtype) - for name, dtype in data.dtypes.items() - if pd.api.types.is_datetime64_any_dtype(dtype) - ] - column_timezones = { - name: str(dtype.tz) - for name, dtype in datetime_columns - if hasattr(dtype, "tz") - } - - index_label = index_table_names - dtype = { - name: Timestamp(getattr(dtype, "tz", False)) - for name, dtype in datetime_columns - } - - index_col = index_table_names - parse_dates = [name for name, dtype in datetime_columns] - - pandas_metadata = { - "read_sql_table": { - "index_col": index_col, - "parse_dates": parse_dates, - "index_names": index_original_names, - "column_timezones": column_timezones, - }, - } - - to_sql_kwargs = { - "index_label": index_label, - "dtype": dtype, - "if_exists": "replace", - } - data.to_sql(symbol, self._engine, **to_sql_kwargs) - - return data - - def read_as_dataframe( - self, symbol, time_column=None, start_time=None, end_time=None - ): - index_col = ["Date"] - parse_dates = ["Date"] - read_sql_table_kwargs = { - "index_col": index_col, - "parse_dates": parse_dates, - } - data = pd.read_sql_table(symbol, self._engine, **read_sql_table_kwargs) - index_names = index_col - index_names = tuple(index_names) - if len(data.index.names) == 1: - index_names = index_names[0] - data.index.rename(index_names, inplace=True) - column_timezones = {} - for column_name in parse_dates: - timezone = column_timezones.get(column_name, Timestamp.local_timezone) - if isinstance(timezone, str): - timezone = pytz.timezone(timezone) - data[column_name] = ( - data[column_name].dt.tz_localize(Timestamp.utc).dt.tz_convert(timezone) - ) - if column_name not in column_timezones: - data[column_name] = data[column_name].dt.tz_localize(None) - return data - - def read_as_cursor(self, symbol, time_column=None, start_time=None, end_time=None): - records = Table(symbol, MetaData(), autoload_with=self._engine) - statement = select(records) - - if time_column is not None: - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - - if start_time is not None: - start_time = pd.Timestamp(start_time) - if time_column is None: - time_column = 0 - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - if Timestamp.is_naive(start_time): - start_time = start_time.tz_localize(Timestamp.local_timezone) - start_time = start_time.astimezone(Timestamp.utc) - statement = statement.where( - time_column >= start_time - ) # pylint: disable=unsubscriptable-object - - if end_time is not None: - end_time = pd.Timestamp(end_time) - if time_column is None: - time_column = 0 - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - if Timestamp.is_naive(end_time): - end_time = end_time.tz_localize(Timestamp.local_timezone) - end_time = end_time.astimezone(Timestamp.utc) - statement = statement.where( - time_column <= end_time - ) # pylint: disable=unsubscriptable-object - - data = self._engine.execute(statement) - return data - - def read(self, *args, **kwargs): - return self.read_as_dataframe(*args, **kwargs) - - def delete(self, symbol): - table = Table(symbol, MetaData(), autoload_with=self._engine) - self._engine.execute(DropTable(table), if_exists=True) diff --git a/koapy/utils/store/SQLiteStore.py b/koapy/utils/store/SQLiteStore.py deleted file mode 100644 index 6af090c6..00000000 --- a/koapy/utils/store/SQLiteStore.py +++ /dev/null @@ -1,82 +0,0 @@ -from sqlalchemy import create_engine, inspect - -from .sqlalchemy.Base import Base -from .sqlalchemy.Library import Library -from .sqlalchemy.Session import Session -from .SQLiteStoreLibrary import SQLiteStoreLibrary - - -class SQLiteStore: - def __init__(self, filename): - self._filename = filename - self._engine = create_engine("sqlite:///" + self._filename) - - Session.configure(bind=self._engine) - - inspector = inspect(self._engine) - table_names = inspector.get_table_names() - - if len(table_names) == 0: - Base.metadata.create_all(self._engine) - inspector = inspect(self._engine) - table_names = inspector.get_table_names() - - assert all(table_name in table_names for table_name in Base.metadata.tables) - - self._session = Session() - self._library_cache = {} - - def list_libraries(self): - libraries = self._session.query(Library).all() - libraries = [library.name for library in libraries] - return libraries - - def _get_library(self, library): - library = self._session.query(Library).filter(Library.name == library).one() - return library - - def library_exists(self, library): - try: - _library = self._get_library(library) - return True - except: - return False - - def initialize_library(self, library): - library_name = library - if not self.library_exists(library_name): - library = Library(name=library_name) - try: - self._session.add(library) - self._session.commit() - except: - self._session.rollback() - raise - - def get_library(self, library): - library_name = library - if library_name in self._library_cache: - return self._library_cache[library_name] - library = self._get_library(library) - library = SQLiteStoreLibrary(self, library) - self._library_cache[library_name] = library - return library - - def get_or_create_library(self, library): - if not self.library_exists(library): - self.initialize_library(library) - library = self.get_library(library) - return library - - def delete_library(self, library): - library_name = library - library = self._get_library(library_name) - try: - library.delete() - self._session.commit() - except: - self._session.rollback() - raise - - def __getitem__(self, library): - return self.get_library(library) diff --git a/koapy/utils/store/SQLiteStoreLibrary.py b/koapy/utils/store/SQLiteStoreLibrary.py deleted file mode 100644 index 8c150387..00000000 --- a/koapy/utils/store/SQLiteStoreLibrary.py +++ /dev/null @@ -1,312 +0,0 @@ -import hashlib - -import pandas as pd -import pytz - -from sqlalchemy import select -from sqlalchemy.orm.exc import NoResultFound -from sqlalchemy.schema import MetaData, Table - -from .misc.VersionedItem import VersionedItem -from .sqlalchemy.Timestamp import Timestamp - - -class SQLiteStoreLibrary: - def __init__(self, store, library): - self._store = store - self._library = library - - self._engine = self._store._engine - self._session = self._store._session - - def list_symbols(self, all_symbols=False, snapshot=None): - if snapshot is not None: - snapshot = self._library.get_snapshot(snapshot) - symbols = snapshot.get_symbols() - else: - symbols = self._library.get_symbols(deleted=all_symbols) - symbols = [symbol.name for symbol in symbols] - return symbols - - def has_symbol(self, symbol): - try: - _symbol = self._library.get_symbol(symbol) - return True - except NoResultFound: - return False - - def list_versions(self, symbol=None, snapshot=None, latest_only=False): - if symbol is not None: - symbol = self._library.get_symbol(symbol) - versions = symbol.get_versions() - elif snapshot is not None: - snapshot = self._library.get_snapshot(snapshot) - versions = snapshot.get_versions() - elif latest_only: - versions = self._library.get_latest_versions() - else: - versions = self._library.get_versions() - versions = [ - { - "symbol": version.symbol.name, - "version": version.version, - "deleted": version.deleted, - "timestamp": version.timestamp, - "snapshots": [snapshot.name for snapshot in version.get_snapshots()], - } - for version in versions - ] - return versions - - def _hash_data(self, data): - return hashlib.sha256( - pd.util.hash_pandas_object(data).values.tobytes() - ).hexdigest() - - def write(self, symbol, data, metadata=None, prune_previous_version=True, **kwargs): - symbol_name = symbol - try: - symbol = self._library.get_or_create_symbol(symbol_name) - - if data is None: - _version = symbol.create_new_version( - user_metadata=metadata, deleted=metadata and metadata.get("deleted") - ) - self._session.commit() - else: - index_original_names = [name for name in data.index.names] - index_table_names = [ - name if name is not None else "index_%d" % i - for i, name in enumerate(data.index.names) - ] - - datetime_columns = [ - (name, dtype) - for name, dtype in data.dtypes.items() - if pd.api.types.is_datetime64_any_dtype(dtype) - ] - column_timezones = { - name: str(dtype.tz) - for name, dtype in datetime_columns - if hasattr(dtype, "tz") - } - - index_label = index_table_names - dtype = { - name: Timestamp(getattr(dtype, "tz", False)) - for name, dtype in datetime_columns - } - - index_col = index_table_names - parse_dates = [name for name, dtype in datetime_columns] - - pandas_metadata = { - "read_sql_table": { - "index_col": index_col, - "parse_dates": parse_dates, - "index_names": index_original_names, - "column_timezones": column_timezones, - }, - } - - table_name = self._hash_data(data) - _version = symbol.create_new_version( - table_name=table_name, - user_metadata=metadata, - pandas_metadata=pandas_metadata, - deleted=metadata and metadata.get("deleted"), - ) - self._session.commit() - - to_sql_kwargs = { - "index_label": index_label, - "dtype": dtype, - "if_exists": "replace", - } - data.to_sql(table_name, self._engine, **to_sql_kwargs) - except: - self._session.rollback() - raise - - if prune_previous_version: - self._prune_previous_versions(symbol_name, **kwargs) - - return self.read(symbol_name) - - def _get_version(self, symbol, as_of=None): - symbol_name = symbol - symbol = self._library.get_symbol(symbol_name) - - if as_of is None: - version = symbol.get_latest_version() - elif isinstance(as_of, int): - version = symbol.get_version_by_number(as_of) - elif isinstance(as_of, str): - snapshot = self._library.get_snapshot(as_of) - version = snapshot.get_version_of_symbol(symbol) - else: - raise ValueError("Invalid as_of argument") - - return version - - def read_as_dataframe( - self, symbol, as_of=None, time_column=None, start_time=None, end_time=None - ): - symbol_name = symbol - version = self._get_version(symbol_name, as_of) - - data = None - - if version.table_name is not None: - read_sql_table_kwargs = { - "index_col": version.pandas_metadata["read_sql_table"]["index_col"], - "parse_dates": version.pandas_metadata["read_sql_table"]["parse_dates"], - } - data = pd.read_sql_table( - version.table_name, self._engine, **read_sql_table_kwargs - ) - index_names = version.pandas_metadata["read_sql_table"]["index_names"] - index_names = tuple(index_names) - if len(data.index.names) == 1: - index_names = index_names[0] - data.index.rename(index_names, inplace=True) # pylint: disable=no-member - column_timezones = version.pandas_metadata["read_sql_table"][ - "column_timezones" - ] - for column_name in version.pandas_metadata["read_sql_table"]["parse_dates"]: - timezone = column_timezones.get(column_name, Timestamp.local_timezone) - if isinstance(timezone, str): - timezone = pytz.timezone(timezone) - data[column_name] = ( - data[column_name] - .dt.tz_localize(Timestamp.utc) - .dt.tz_convert(timezone) - ) - if column_name not in column_timezones: - data[column_name] = data[column_name].dt.tz_localize(None) - - return VersionedItem( - self._library.name, - symbol_name, - version.version, - version.timestamp, - data, - version.user_metadata, - ) - - def read_as_cursor( - self, symbol, as_of=None, time_column=None, start_time=None, end_time=None - ): - symbol_name = symbol - version = self._get_version(symbol_name, as_of) - - cursor = None - - if version.table_name is not None: - records = Table(version.table_name, MetaData(), autoload_with=self._engine) - statement = select(records) - - if time_column is not None: - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - - if start_time is not None: - start_time = pd.Timestamp(start_time) - if time_column is None: - time_column = 0 - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - if Timestamp.is_naive(start_time): - start_time = start_time.tz_localize(Timestamp.local_timezone) - start_time = start_time.astimezone(Timestamp.utc) - statement = statement.where( - time_column >= start_time - ) # pylint: disable=unsubscriptable-object - - if end_time is not None: - end_time = pd.Timestamp(end_time) - if time_column is None: - time_column = 0 - time_column = records.columns[ - time_column - ] # pylint: disable=unsubscriptable-object - statement = statement.order_by(time_column) - if Timestamp.is_naive(end_time): - end_time = end_time.tz_localize(Timestamp.local_timezone) - end_time = end_time.astimezone(Timestamp.utc) - statement = statement.where( - time_column <= end_time - ) # pylint: disable=unsubscriptable-object - - statement = statement.execution_options(stream_results=True) - - cursor = self._session.execute(statement) - - return VersionedItem( - self._library.name, - symbol_name, - version.version, - version.timestamp, - cursor, - version.user_metadata, - ) - - def read(self, *args, **kwargs): - return self.read_as_dataframe(*args, **kwargs) - - def _prune_previous_versions(self, symbol, keep_mins=120): - symbol_name = symbol - symbol = self._library.get_symbol(symbol_name) - prunable_verions = symbol.get_prunable_versions(keep_mins) - try: - for version in prunable_verions: - version.delete() - self._session.commit() - except: - self._session.rollback() - raise - - def _delete_version(self, symbol, version): - symbol = self._library.get_symbol(symbol) - version = symbol.get_version_by_number(version, deleted=True) - try: - version.delete() - self._session.commit() - except: - self._session.rollback() - raise - - def delete(self, symbol): - symbol_name = symbol - symbol = self._library.get_symbol(symbol_name) - _sentinel = self.write( - symbol_name, None, prune_previous_version=False, metadata={"deleted": True} - ) - self._prune_previous_versions(symbol_name, 0) - assert not self.has_symbol(symbol_name) - - def list_snapshots(self): - snapshots = self._library.snapshots - snapshots = [snapshot.name for snapshot in snapshots] - return snapshots - - def snapshot(self, snapshot): - try: - self._library.create_snapshot(snapshot) - self._session.commit() - except: - self._session.rollback() - raise - - def delete_snapshot(self, snapshot): - snapshot = self._library.get_snapshot(snapshot) - try: - snapshot.delete() - self._session.commit() - except: - self._session.rollback() - raise diff --git a/koapy/utils/store/__init__.py b/koapy/utils/store/__init__.py deleted file mode 100644 index ac8ed8ff..00000000 --- a/koapy/utils/store/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .SQLiteStore import SQLiteStore diff --git a/koapy/utils/store/misc/VersionedItem.py b/koapy/utils/store/misc/VersionedItem.py deleted file mode 100644 index 7b0d9fa1..00000000 --- a/koapy/utils/store/misc/VersionedItem.py +++ /dev/null @@ -1,20 +0,0 @@ -class VersionedItem: - def __init__(self, library, symbol, version, timestamp, data, metadata): - self.library = library - self.symbol = symbol - self.version = version - self.timestamp = timestamp - self.data = data - self.metadata = metadata - - def __repr__(self): - return ", metadata={!r})>".format( - self.library, - self.symbol, - self.version, - self.timestamp, - type(self.data).__module__, - type(self.data).__name__, - hex(id(self.data)), - self.metadata, - ) diff --git a/koapy/utils/store/misc/__init__.py b/koapy/utils/store/misc/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/store/sqlalchemy/Base.py b/koapy/utils/store/sqlalchemy/Base.py deleted file mode 100644 index 59be7030..00000000 --- a/koapy/utils/store/sqlalchemy/Base.py +++ /dev/null @@ -1,3 +0,0 @@ -from sqlalchemy.orm import declarative_base - -Base = declarative_base() diff --git a/koapy/utils/store/sqlalchemy/Library.py b/koapy/utils/store/sqlalchemy/Library.py deleted file mode 100644 index 85ef0440..00000000 --- a/koapy/utils/store/sqlalchemy/Library.py +++ /dev/null @@ -1,129 +0,0 @@ -from sqlalchemy import Column, Integer, String, func -from sqlalchemy.orm import aliased, object_session, relationship -from sqlalchemy.orm.exc import NoResultFound - -from .Base import Base -from .Snapshot import Snapshot -from .SnapshotAssociation import SnapshotAssociation -from .Symbol import Symbol -from .Version import Version - - -class Library(Base): - __tablename__ = "libraries" - - id = Column(Integer, primary_key=True) - name = Column(String, unique=True, index=True, nullable=False) - - symbols = relationship("Symbol", back_populates="library") - snapshots = relationship("Snapshot", back_populates="library") - - def get_symbol(self, symbol, deleted=False): - symbol_name = symbol - session = object_session(self) - symbol = ( - session.query(Symbol).with_parent(self).filter(Symbol.name == symbol_name) - ) - symbol = symbol.one() - if not deleted: - _version = symbol.get_latest_version() - return symbol - - def get_or_create_symbol(self, symbol): - symbol_name = symbol - try: - symbol = self.get_symbol(symbol_name, deleted=True) - except NoResultFound: - symbol = Symbol(name=symbol_name) - self.symbols.append(symbol) - return symbol - - def get_symbols(self, deleted=False): - if deleted: - return self.symbols - - session = object_session(self) - - symbols = session.query(Symbol).with_parent(self) - - versions = session.query(Version, func.max(Version.version)).group_by( - Version.symbol_id - ) - version = aliased(Version, alias=versions.subquery()) - versions = session.query(version) - - if not deleted: - versions = versions.filter(version.deleted != True) - - symbols = symbols.join(versions.subquery()) - symbols = symbols.all() - return symbols - - def get_versions(self, deleted=False): - session = object_session(self) - - symbols = session.query(Symbol).with_parent(self) - versions = session.query(Version).join(symbols.subquery()) - - if not deleted: - versions = versions.filter(Version.deleted != True) - - versions = versions.all() - return versions - - def get_latest_versions(self, deleted=False): - session = object_session(self) - - symbols = session.query(Symbol).with_parent(self) - - versions = session.query(Version, func.max(Version.version)).group_by( - Version.symbol_id - ) - version = aliased(Version, alias=versions.subquery()) - versions = session.query(version) - - if not deleted: - versions = versions.filter(version.deleted != True) - - versions = versions.join(symbols.subquery()) - versions = versions.all() - return versions - - def get_snapshot(self, snapshot): - snapshot_name = snapshot - session = object_session(self) - snapshot = ( - session.query(Snapshot) - .with_parent(self) - .filter(Snapshot.name == snapshot_name) - .one() - ) - return snapshot - - def create_snapshot(self, snapshot): - snapshot_name = snapshot - snapshot = Snapshot(name=snapshot_name) - - versions = self.get_latest_versions() - associations = [SnapshotAssociation(version=version) for version in versions] - snapshot.versions.extend(associations) - - self.snapshots.append(snapshot) - return snapshot - - def delete(self): - session = object_session(self) - - symbols = session.query(Symbol).with_parent(self) - versions = session.query(Version).join(symbols) - - snapshots = session.query(Snapshot).with_parent(self) - associations = session.query(SnapshotAssociation).join(snapshots) - - associations.delete() - snapshots.delete() - - versions.delete() - symbols.delete() - - session.delete(self) diff --git a/koapy/utils/store/sqlalchemy/Session.py b/koapy/utils/store/sqlalchemy/Session.py deleted file mode 100644 index 8fb28d33..00000000 --- a/koapy/utils/store/sqlalchemy/Session.py +++ /dev/null @@ -1,3 +0,0 @@ -from sqlalchemy.orm import sessionmaker - -Session = sessionmaker() diff --git a/koapy/utils/store/sqlalchemy/Snapshot.py b/koapy/utils/store/sqlalchemy/Snapshot.py deleted file mode 100644 index 495407f6..00000000 --- a/koapy/utils/store/sqlalchemy/Snapshot.py +++ /dev/null @@ -1,63 +0,0 @@ -from sqlalchemy import Column, ForeignKey, Integer, String, UniqueConstraint -from sqlalchemy.orm import object_session, relationship -from sqlalchemy.sql.functions import current_timestamp - -from .Base import Base -from .SnapshotAssociation import SnapshotAssociation -from .Symbol import Symbol -from .Timestamp import Timestamp -from .Version import Version - - -class Snapshot(Base): - __tablename__ = "snapshots" - - id = Column(Integer, primary_key=True) - name = Column(String, index=True, nullable=False) - - timestamp = Column(Timestamp(timezone=True), server_default=current_timestamp()) - - library_id = Column(Integer, ForeignKey("libraries.id"), nullable=False) - library = relationship("Library", back_populates="snapshots") - - versions = relationship("SnapshotAssociation", back_populates="snapshot") - - __table_args__ = (UniqueConstraint("library_id", "name"),) - - def get_symbols(self): - session = object_session(self) - associations = session.query(SnapshotAssociation).with_parent(self) - versions = session.query(Version).join(associations.subquery()) - symbols = session.query(Symbol).join(versions.subquery()) - symbols = symbols.all() - return symbols - - def get_versions(self): - session = object_session(self) - associations = session.query(SnapshotAssociation).with_parent(self) - versions = session.query(Version).join(associations.subquery()) - versions = versions.all() - return versions - - def get_version_of_symbol(self, symbol): - session = object_session(self) - if isinstance(symbol, str): - symbol = ( - session.query(Symbol) - .filter(Symbol.library_id == self.library_id and Symbol.name == symbol) - .one() - ) - associations = session.query(SnapshotAssociation).with_parent(self) - version = ( - session.query(Version) - .with_parent(symbol) - .join(associations.subquery()) - .one() - ) - return version - - def delete(self): - session = object_session(self) - associations = session.query(SnapshotAssociation).with_parent(self) - associations.delete() - session.delete(self) diff --git a/koapy/utils/store/sqlalchemy/SnapshotAssociation.py b/koapy/utils/store/sqlalchemy/SnapshotAssociation.py deleted file mode 100644 index 3bf27331..00000000 --- a/koapy/utils/store/sqlalchemy/SnapshotAssociation.py +++ /dev/null @@ -1,14 +0,0 @@ -from sqlalchemy import Column, ForeignKey, Integer -from sqlalchemy.orm import relationship - -from .Base import Base - - -class SnapshotAssociation(Base): - __tablename__ = "snapshot_associations" - - snapshot_id = Column(Integer, ForeignKey("snapshots.id"), primary_key=True) - version_id = Column(Integer, ForeignKey("versions.id"), primary_key=True) - - snapshot = relationship("Snapshot", back_populates="versions") - version = relationship("Version", back_populates="snapshots") diff --git a/koapy/utils/store/sqlalchemy/Symbol.py b/koapy/utils/store/sqlalchemy/Symbol.py deleted file mode 100644 index 48036882..00000000 --- a/koapy/utils/store/sqlalchemy/Symbol.py +++ /dev/null @@ -1,107 +0,0 @@ -import pandas as pd - -from sqlalchemy import Column, ForeignKey, Integer, String, UniqueConstraint, func -from sqlalchemy.orm import aliased, object_session, relationship -from sqlalchemy.orm.exc import NoResultFound - -from .Base import Base -from .SnapshotAssociation import SnapshotAssociation -from .Version import Version - - -class Symbol(Base): - __tablename__ = "symbols" - - id = Column(Integer, primary_key=True) - name = Column(String, index=True, nullable=False) - - library_id = Column(Integer, ForeignKey("libraries.id"), nullable=False) - library = relationship("Library", back_populates="symbols") - - versions = relationship( - "Version", back_populates="symbol", order_by="Version.version" - ) - - __table_args__ = (UniqueConstraint("library_id", "name"),) - - def get_versions(self, deleted=False): - """ - versions = self.versions - if not deleted: - versions = [version for version in versions if not version.deleted] - """ - session = object_session(self) - versions = session.query(Version).with_parent(self) - version = aliased(Version, alias=versions.subquery()) - versions = session.query(version) - if not deleted: - versions = versions.filter(version.deleted != True) - versions = versions.order_by(version.version) - versions = versions.all() - return versions - - def get_latest_version(self, deleted=False): - """ - versions = self.versions - if len(versions) == 0: - raise NoResultFound - latest_version = self.versions[-1] - if not deleted and latest_version.deleted: - raise NoResultFound - """ - session = object_session(self) - latest_version = session.query(Version, func.max(Version.version)).with_parent( - self - ) - version = aliased(Version, alias=latest_version.subquery()) - latest_version = session.query(version) - if not deleted: - latest_version = latest_version.filter(version.deleted != True) - latest_version = latest_version.one() - return latest_version - - def create_new_version( - self, table_name=None, user_metadata=None, pandas_metadata=None, deleted=None - ): - try: - latest_version = self.get_latest_version() - except NoResultFound: - next_version = 0 - else: - next_version = latest_version.version + 1 - new_version = Version( - version=next_version, - table_name=table_name, - user_metadata=user_metadata, - pandas_metadata=pandas_metadata, - deleted=deleted, - ) - self.versions.append(new_version) - return new_version - - def get_version_by_number(self, version_number, deleted=False): - session = object_session(self) - version = ( - session.query(Version) - .with_parent(self) - .filter(Version.version == version_number) - ) - if not deleted: - version = version.filter(Version.deleted != True) - version = version.one() - return version - - def get_prunable_versions(self, keep_mins=120): - session = object_session(self) - versions = session.query(Version).with_parent(self) - latest_version = self.get_latest_version(deleted=True) - keep_mins_seconds = keep_mins * 60 - latest_timestamp = latest_version.timestamp - oldest_timestamp = latest_timestamp - pd.Timedelta(keep_mins_seconds, unit="s") - prunable_verions = ( - versions.outerjoin(SnapshotAssociation) - .filter(SnapshotAssociation.version_id == None) - .filter(Version.timestamp < oldest_timestamp) - ) - prunable_verions = prunable_verions.all() - return prunable_verions diff --git a/koapy/utils/store/sqlalchemy/Timestamp.py b/koapy/utils/store/sqlalchemy/Timestamp.py deleted file mode 100644 index 183a2f40..00000000 --- a/koapy/utils/store/sqlalchemy/Timestamp.py +++ /dev/null @@ -1,47 +0,0 @@ -import datetime -import inspect - -import pytz - -from sqlalchemy import DateTime -from sqlalchemy.types import TypeDecorator - - -class Timestamp(TypeDecorator): # pylint: disable=abstract-method - - impl = DateTime - cache_ok = True - - signature = inspect.signature(impl) - - utc = datetime.timezone.utc - local_timezone = datetime.datetime.now().astimezone().tzinfo - - def __init__(self, *args, **kwargs): - self._timezone = self.local_timezone - bound = self.signature.bind(*args, **kwargs) - bound.apply_defaults() - if bound.arguments["timezone"]: - if not isinstance(bound.arguments["timezone"], bool): - self._timezone = bound.arguments["timezone"] - bound.arguments["timezone"] = True - if isinstance(self._timezone, str): - self._timezone = pytz.timezone(self._timezone) - super().__init__(*bound.args, **bound.kwargs) - - @classmethod - def is_naive(cls, value): - return value.tzinfo is None or value.tzinfo.utcoffset(value) is None - - def process_bind_param(self, value, dialect): - if self.is_naive(value): - value = value.replace(tzinfo=self.local_timezone) - return value.astimezone(self.utc) - - def process_result_value(self, value, dialect): - if self.is_naive(value): - value = value.replace(tzinfo=self.utc) - value = value.astimezone(self._timezone) - if not self.timezone: - value = value.replace(tzinfo=None) - return value diff --git a/koapy/utils/store/sqlalchemy/Version.py b/koapy/utils/store/sqlalchemy/Version.py deleted file mode 100644 index e9cdb9be..00000000 --- a/koapy/utils/store/sqlalchemy/Version.py +++ /dev/null @@ -1,62 +0,0 @@ -from sqlalchemy import ( - Boolean, - Column, - ForeignKey, - Integer, - PickleType, - String, - UniqueConstraint, -) -from sqlalchemy.orm import object_session, relationship -from sqlalchemy.schema import DropTable, MetaData, Table -from sqlalchemy.sql.functions import current_timestamp - -from .Base import Base -from .Timestamp import Timestamp - - -class Version(Base): - __tablename__ = "versions" - - id = Column(Integer, primary_key=True) - version = Column(Integer, nullable=False) - - table_name = Column(String) - user_metadata = Column(PickleType) - pandas_metadata = Column(PickleType) - - deleted = Column(Boolean, default=False) - - timestamp = Column(Timestamp(timezone=True), server_default=current_timestamp()) - - symbol_id = Column(Integer, ForeignKey("symbols.id")) - symbol = relationship("Symbol", back_populates="versions") - - snapshots = relationship("SnapshotAssociation", back_populates="version") - - __table_args__ = (UniqueConstraint("symbol_id", "version"),) - - def get_snapshots(self): - # quick fix fir circular dependency - from .Snapshot import Snapshot - from .SnapshotAssociation import SnapshotAssociation - - session = object_session(self) - snapshots = session.query(SnapshotAssociation).with_parent(self) - snapshots = session.query(Snapshot).join(snapshots.subquery()) - snapshots = snapshots.all() - return snapshots - - def delete(self): - session = object_session(self) - if self.table_name is not None: - table_reference_count = ( - session.query(Version) - .filter(Version.table_name == self.table_name) - .count() - ) - if table_reference_count <= 1: - session.execute( - DropTable(Table(self.table_name, MetaData()), if_exists=True) - ) - session.delete(self) diff --git a/koapy/utils/store/sqlalchemy/__init__.py b/koapy/utils/store/sqlalchemy/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/koapy/utils/subprocess.py b/koapy/utils/subprocess.py deleted file mode 100644 index 597d29e7..00000000 --- a/koapy/utils/subprocess.py +++ /dev/null @@ -1,152 +0,0 @@ -import inspect -import subprocess -import sys -import textwrap - -from koapy.utils.logging import get_logger - -logger = get_logger(__name__) - - -def function_to_script(func): - function_sig = inspect.signature(func) - assert all( - p.default != p.empty for p in function_sig.parameters - ), "Function should not require any parameters" - - function_name = func.__name__ - function_impl = inspect.getsource(func) - function_impl = textwrap.dedent(function_impl) - - script = ( - textwrap.dedent( - """ - %s - - if __name__ == '__main__': - %s() - """ - ) - % (function_impl, function_name) - ) - - return script - - -def function_to_subprocess_args(func, executable=None): - if executable is None: - executable = sys.executable - script = function_to_script(func) - args = [executable, "-c", script] - return args - - -def run_file(filename, *args, executable=None, **kwargs): - if executable is None: - executable = sys.executable - cmd = [executable, filename] - return subprocess.check_call(cmd, *args, **kwargs) - - -def run_script(script, *args, executable=None, **kwargs): - if executable is None: - executable = sys.executable - cmd = [executable, "-c", script] - return subprocess.check_call(cmd, *args, **kwargs) - - -def run_function(function, *args, executable=None, **kwargs): - script = function_to_script(function) - return run_script(script, *args, executable=executable, **kwargs) - - -def quote(s): - return '"' + s.replace('"', '`"') + '"' - - -def run_as_admin(cmd, cwd=None, check=True, wait=True): - import win32con - import win32event - import win32process - - # pyright: reportMissingImports=false - # pylint: disable=import-error,no-name-in-module - from win32com.shell import shellcon - from win32com.shell.shell import ShellExecuteEx - - kwargs = dict( - nShow=win32con.SW_SHOWNORMAL, - fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, - lpVerb="runas", - lpFile=cmd[0], - lpParameters=" ".join(cmd[1:]), - ) - - if cwd is not None: - kwargs["lpDirectory"] = cwd - - logger.info("Running command: %s", " ".join(cmd)) - procInfo = ShellExecuteEx(**kwargs) - - if check or wait: - procHandle = procInfo["hProcess"] - _ = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) - rc = win32process.GetExitCodeProcess(procHandle) - logger.info("Process handle %s returned code %d", procHandle, rc) - if check and rc < 0: - raise subprocess.CalledProcessError(rc, cmd) - else: - rc = None - - return rc - - -def create_job_object_for_cleanup(): - # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s - import win32job - - jobAttributes = None - jobName = "" - hJob = win32job.CreateJobObject(jobAttributes, jobName) - extendedInfo = win32job.QueryInformationJobObject( - hJob, win32job.JobObjectExtendedLimitInformation - ) - basicLimitInformation = extendedInfo["BasicLimitInformation"] - basicLimitInformation["LimitFlags"] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE - win32job.SetInformationJobObject( - hJob, - win32job.JobObjectExtendedLimitInformation, - extendedInfo, - ) - return hJob - - -job_handle = create_job_object_for_cleanup() - - -def make_process_die_when_parent_dies(pid): - assert pid != 0 - - # https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies/23587108#23587108s - import win32api - import win32con - import win32job - - desiredAccess = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA - inheritHandle = False - hProcess = win32api.OpenProcess( - desiredAccess, - inheritHandle, - pid, - ) - # process will be terminated when job is destroyed - # job will be destroyed when its last handle is closed - # job handle will be closed when it loses its reference, hJob in this case - hJob = job_handle - win32job.AssignProcessToJobObject(hJob, hProcess) - - -class Popen(subprocess.Popen): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - make_process_die_when_parent_dies(self.pid) diff --git a/koapy/utils/threading.py b/koapy/utils/threading.py deleted file mode 100644 index 5c87ced6..00000000 --- a/koapy/utils/threading.py +++ /dev/null @@ -1,19 +0,0 @@ -import threading - - -class Singleton: - - _instance = None - _lock = threading.RLock() - - @classmethod - def _get_instance_without_check(cls, *args, **kwargs): - return cls._instance - - @classmethod - def get_instance(cls, *args, **kwargs): - with cls._lock: - if not isinstance(cls._instance, cls): - cls._instance = cls(*args, **kwargs) - cls.get_instance = cls._get_instance_without_check - return cls._instance diff --git a/notebooks/getting-historical-stock-price-data.html b/notebooks/getting-historical-stock-price-data.html new file mode 100644 index 00000000..ce21a403 --- /dev/null +++ b/notebooks/getting-historical-stock-price-data.html @@ -0,0 +1,20565 @@ + + + + + + + + + Getting historical stock price data — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Getting historical stock price data

+ + + + + +getting-historical-stock-price-data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/notebooks/index.html b/notebooks/index.html new file mode 100644 index 00000000..96a0d82d --- /dev/null +++ b/notebooks/index.html @@ -0,0 +1,160 @@ + + + + + + + + + Notebooks — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Notebooks

+ +
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/notebooks/koapy-tutorial.html b/notebooks/koapy-tutorial.html new file mode 100644 index 00000000..cd5994a5 --- /dev/null +++ b/notebooks/koapy-tutorial.html @@ -0,0 +1,22305 @@ + + + + + + + + + KOAPY Tutorial — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

KOAPY Tutorial

+ + + + + +koapy-tutorial + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..85b929f3 Binary files /dev/null and b/objects.inv differ diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index baa09f48..00000000 --- a/poetry.lock +++ /dev/null @@ -1,3824 +0,0 @@ -[[package]] -name = "actions-toolkit" -version = "0.1.14" -description = "🛠 The GitHub ToolKit for developing GitHub Actions in Python." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -PyGithub = "*" -requests = "*" - -[[package]] -name = "aiohttp" -version = "3.8.3" -description = "Async http client/server framework (asyncio)" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -aiosignal = ">=1.1.2" -async-timeout = ">=4.0.0a3,<5.0" -attrs = ">=17.3.0" -charset-normalizer = ">=2.0,<3.0" -frozenlist = ">=1.1.1" -multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" - -[package.extras] -speedups = ["Brotli", "aiodns", "cchardet"] - -[[package]] -name = "aiosignal" -version = "1.2.0" -description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -frozenlist = ">=1.1.0" - -[[package]] -name = "alabaster" -version = "0.7.12" -description = "A configurable sidebar-enabled Sphinx theme" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "astroid" -version = "2.12.10" -description = "An abstract syntax tree for Python with inference support." -category = "dev" -optional = false -python-versions = ">=3.7.2" - -[package.dependencies] -lazy-object-proxy = ">=1.4.0" -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} -wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} - -[[package]] -name = "asttokens" -version = "2.0.8" -description = "Annotate AST trees with source code positions" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -six = "*" - -[package.extras] -test = ["astroid (<=2.5.3)", "pytest"] - -[[package]] -name = "astunparse" -version = "1.6.3" -description = "An AST unparser for Python" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -six = ">=1.6.1,<2.0" -wheel = ">=0.23.0,<1.0" - -[[package]] -name = "async-timeout" -version = "4.0.2" -description = "Timeout context manager for asyncio programs" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.5" - -[package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] - -[[package]] -name = "Babel" -version = "2.10.3" -description = "Internationalization utilities" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pytz = ">=2015.7" - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "backports.zoneinfo" -version = "0.2.1" -description = "Backport of the standard library zoneinfo module" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -tzdata = ["tzdata"] - -[[package]] -name = "beautifulsoup4" -version = "4.11.1" -description = "Screen-scraping library" -category = "dev" -optional = false -python-versions = ">=3.6.0" - -[package.dependencies] -soupsieve = ">1.2" - -[package.extras] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "black" -version = "22.10.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "bleach" -version = "5.0.1" -description = "An easy safelist-based HTML-sanitizing tool." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -six = ">=1.9.0" -webencodings = "*" - -[package.extras] -css = ["tinycss2 (>=1.1.0,<1.2)"] -dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "mypy (==0.961)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)"] - -[[package]] -name = "build" -version = "0.8.0" -description = "A simple, correct PEP 517 build frontend" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -colorama = {version = "*", markers = "os_name == \"nt\""} -packaging = ">=19.0" -pep517 = ">=0.9.1" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -docs = ["furo (>=2021.08.31)", "sphinx (>=4.0,<5.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)"] -test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "toml (>=0.10.0)", "wheel (>=0.36.0)"] -typing = ["importlib-metadata (>=4.6.4)", "mypy (==0.950)", "typing-extensions (>=3.7.4.3)"] -virtualenv = ["virtualenv (>=20.0.35)"] - -[[package]] -name = "bump2version" -version = "1.0.1" -description = "Version-bump your software with a single command!" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "certifi" -version = "2022.9.24" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "cffi" -version = "1.15.1" -description = "Foreign Function Interface for Python calling C code." -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "cfgv" -version = "3.3.1" -description = "Validate configuration and produce human readable error messages." -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[[package]] -name = "charset-normalizer" -version = "2.1.1" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" -optional = false -python-versions = ">=3.6.0" - -[package.extras] -unicode_backport = ["unicodedata2"] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "codecov" -version = "2.1.12" -description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -coverage = "*" -requests = ">=2.7.9" - -[[package]] -name = "colorama" -version = "0.4.5" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "comtypes" -version = "1.1.14" -description = "Pure Python COM package" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "coverage" -version = "6.5.0" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "cryptography" -version = "38.0.1" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = ">=1.12" - -[package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools-rust (>=0.11.4)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] - -[[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "defusedxml" -version = "0.7.1" -description = "XML bomb protection for Python stdlib modules" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "Deprecated" -version = "1.2.13" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -wrapt = ">=1.10,<2" - -[package.extras] -dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] - -[[package]] -name = "dill" -version = "0.3.5.1" -description = "serialize all of python" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" - -[package.extras] -graph = ["objgraph (>=1.7.2)"] - -[[package]] -name = "discord.py" -version = "2.0.1" -description = "A Python wrapper for the Discord API" -category = "main" -optional = false -python-versions = ">=3.8.0" - -[package.dependencies] -aiohttp = ">=3.7.4,<4" - -[package.extras] -docs = ["sphinx (==4.4.0)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport", "typing-extensions (>=4.3,<5)"] -speed = ["Brotli", "aiodns (>=1.1)", "cchardet (==2.1.7)", "orjson (>=3.5.4)"] -test = ["coverage[toml]", "pytest", "pytest-asyncio", "pytest-cov", "pytest-mock", "typing-extensions (>=4.3,<5)"] -voice = ["PyNaCl (>=1.3.0,<1.6)"] - -[[package]] -name = "distlib" -version = "0.3.6" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "docutils" -version = "0.19" -description = "Docutils -- Python Documentation Utilities" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "dunamai" -version = "1.13.1" -description = "Dynamic version generation" -category = "dev" -optional = false -python-versions = ">=3.5,<4.0" - -[package.dependencies] -packaging = ">=20.9" - -[[package]] -name = "entrypoints" -version = "0.4" -description = "Discover and load entry points from installed packages." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "et-xmlfile" -version = "1.1.0" -description = "An implementation of lxml.xmlfile for the standard library" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "exchange-calendars" -version = "4.2.3" -description = "Calendars for securities exchanges" -category = "main" -optional = false -python-versions = "~=3.8" - -[package.dependencies] -korean-lunar-calendar = "*" -numpy = "*" -pandas = ">=1.1" -pyluach = "*" -python-dateutil = "*" -pytz = "*" -toolz = "*" - -[package.extras] -dev = ["flake8", "hypothesis", "pip-tools", "pytest", "pytest-benchmark", "pytest-xdist"] - -[[package]] -name = "execnet" -version = "1.9.0" -description = "execnet: rapid multi-Python deployment" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.extras] -testing = ["pre-commit"] - -[[package]] -name = "executing" -version = "1.1.1" -description = "Get the currently executing AST node of a frame, and other information" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] - -[[package]] -name = "fastjsonschema" -version = "2.16.2" -description = "Fastest Python implementation of JSON schema" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] - -[[package]] -name = "filelock" -version = "3.8.0" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] -testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "flake8" -version = "5.0.4" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.9.0,<2.10.0" -pyflakes = ">=2.5.0,<2.6.0" - -[[package]] -name = "frozenlist" -version = "1.3.1" -description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "greenlet" -version = "1.1.3" -description = "Lightweight in-process concurrent programming" -category = "main" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" - -[package.extras] -docs = ["Sphinx"] - -[[package]] -name = "grpcio" -version = "1.48.2" -description = "HTTP/2-based RPC framework" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -six = ">=1.5.2" - -[package.extras] -protobuf = ["grpcio-tools (>=1.48.2)"] - -[[package]] -name = "grpcio-tools" -version = "1.48.2" -description = "Protobuf code generator for gRPC" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -grpcio = ">=1.48.2" -protobuf = ">=3.12.0,<4.0dev" -setuptools = "*" - -[[package]] -name = "identify" -version = "2.5.6" -description = "File identification library for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.4" -description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "imagesize" -version = "1.4.1" -description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "importlib-metadata" -version = "5.0.0" -description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] - -[[package]] -name = "importlib-resources" -version = "5.10.0" -description = "Read resources from Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[[package]] -name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "ipython" -version = "8.5.0" -description = "IPython: Productive Interactive Computing" -category = "dev" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -decorator = "*" -jedi = ">=0.16" -matplotlib-inline = "*" -pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">3.0.1,<3.1.0" -pygments = ">=2.4.0" -stack-data = "*" -traitlets = ">=5" - -[package.extras] -all = ["Sphinx (>=1.3)", "black", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "testpath", "trio"] -black = ["black"] -doc = ["Sphinx (>=1.3)"] -kernel = ["ipykernel"] -nbconvert = ["nbconvert"] -nbformat = ["nbformat"] -notebook = ["ipywidgets", "notebook"] -parallel = ["ipyparallel"] -qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test_extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] - -[[package]] -name = "isort" -version = "5.10.1" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] - -[[package]] -name = "jedi" -version = "0.18.1" -description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -parso = ">=0.8.0,<0.9.0" - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] - -[[package]] -name = "Jinja2" -version = "3.1.2" -description = "A very fast and expressive template engine." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "jsonschema" -version = "4.16.0" -description = "An implementation of JSON Schema validation for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=17.4.0" -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} -pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} -pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] - -[[package]] -name = "jupyter-client" -version = "7.3.5" -description = "Jupyter protocol implementation and client libraries" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -entrypoints = "*" -jupyter-core = ">=4.9.2" -nest-asyncio = ">=1.5.4" -python-dateutil = ">=2.8.2" -pyzmq = ">=23.0" -tornado = ">=6.2" -traitlets = "*" - -[package.extras] -doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] -test = ["codecov", "coverage", "ipykernel (>=6.5)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "jupyter-core" -version = "4.11.1" -description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} -traitlets = "*" - -[package.extras] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "jupyterlab-pygments" -version = "0.2.2" -description = "Pygments theme using JupyterLab CSS variables" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "korean-lunar-calendar" -version = "0.3.1" -description = "Korean Lunar Calendar" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "lazy-object-proxy" -version = "1.7.1" -description = "A fast and thorough lazy object proxy." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "lxml" -version = "4.9.1" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" - -[package.extras] -cssselect = ["cssselect (>=0.7)"] -html5 = ["html5lib"] -htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] - -[[package]] -name = "MarkupSafe" -version = "2.1.1" -description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "matplotlib-inline" -version = "0.1.6" -description = "Inline Matplotlib backend for Jupyter" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -traitlets = "*" - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mistune" -version = "2.0.4" -description = "A sane Markdown parser with useful plugins and renderers" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "multidict" -version = "6.0.2" -description = "multidict implementation" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "mypy" -version = "0.982" -description = "Optional static typing for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "nbclient" -version = "0.7.0" -description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -category = "dev" -optional = false -python-versions = ">=3.7.0" - -[package.dependencies] -jupyter-client = ">=6.1.5" -nbformat = ">=5.0" -nest-asyncio = "*" -traitlets = ">=5.2.2" - -[package.extras] -sphinx = ["Sphinx (>=1.7)", "autodoc-traits", "mock", "moto", "myst-parser", "sphinx-book-theme"] -test = ["black", "check-manifest", "flake8", "ipykernel", "ipython", "ipywidgets", "mypy", "nbconvert", "pip (>=18.1)", "pre-commit", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "setuptools (>=60.0)", "testpath", "twine (>=1.11.0)", "xmltodict"] - -[[package]] -name = "nbconvert" -version = "7.2.1" -description = "Converting Jupyter Notebooks" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -beautifulsoup4 = "*" -bleach = "*" -defusedxml = "*" -importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} -jinja2 = ">=3.0" -jupyter-core = ">=4.7" -jupyterlab-pygments = "*" -markupsafe = ">=2.0" -mistune = ">=2.0.3,<3" -nbclient = ">=0.5.0" -nbformat = ">=5.1" -packaging = "*" -pandocfilters = ">=1.4.1" -pygments = ">=2.4.1" -tinycss2 = "*" -traitlets = ">=5.0" - -[package.extras] -all = ["ipykernel", "ipython", "ipywidgets (>=7)", "myst-parser", "nbsphinx (>=0.2.12)", "pre-commit", "pyppeteer (>=1,<1.1)", "pyqtwebengine (>=5.15)", "pytest", "pytest-cov", "pytest-dependency", "sphinx (==5.0.2)", "sphinx-rtd-theme", "tornado (>=6.1)"] -docs = ["ipython", "myst-parser", "nbsphinx (>=0.2.12)", "sphinx (==5.0.2)", "sphinx-rtd-theme"] -qtpdf = ["pyqtwebengine (>=5.15)"] -qtpng = ["pyqtwebengine (>=5.15)"] -serve = ["tornado (>=6.1)"] -test = ["ipykernel", "ipywidgets (>=7)", "pre-commit", "pyppeteer (>=1,<1.1)", "pytest", "pytest-cov", "pytest-dependency"] -webpdf = ["pyppeteer (>=1,<1.1)"] - -[[package]] -name = "nbformat" -version = "5.6.1" -description = "The Jupyter Notebook format" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -fastjsonschema = "*" -jsonschema = ">=2.6" -jupyter-core = "*" -traitlets = ">=5.1" - -[package.extras] -test = ["check-manifest", "pep440", "pre-commit", "pytest", "testpath"] - -[[package]] -name = "nbsphinx" -version = "0.8.9" -description = "Jupyter Notebook Tools for Sphinx" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -docutils = "*" -jinja2 = "*" -nbconvert = "!=5.4" -nbformat = "*" -sphinx = ">=1.8" -traitlets = ">=5" - -[[package]] -name = "nest-asyncio" -version = "1.5.6" -description = "Patch asyncio to allow nested event loops" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "nodeenv" -version = "1.7.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "numpy" -version = "1.23.3" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" -optional = false -python-versions = ">=3.8" - -[[package]] -name = "openpyxl" -version = "3.0.10" -description = "A Python library to read/write Excel 2010 xlsx/xlsm files" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -et-xmlfile = "*" - -[[package]] -name = "packaging" -version = "21.3" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - -[[package]] -name = "pandas" -version = "1.5.0" -description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" -optional = false -python-versions = ">=3.8" - -[package.dependencies] -numpy = [ - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, -] -python-dateutil = ">=2.8.1" -pytz = ">=2020.1" - -[package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] - -[[package]] -name = "pandocfilters" -version = "1.5.0" -description = "Utilities for writing pandoc filters in python" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "parso" -version = "0.8.3" -description = "A Python Parser" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] - -[[package]] -name = "pathspec" -version = "0.10.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pep517" -version = "0.13.0" -description = "Wrappers to build Python packages using PEP 517 hooks" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "pexpect" -version = "4.8.0" -description = "Pexpect allows easy control of interactive console applications." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -ptyprocess = ">=0.5" - -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "pip" -version = "22.2.2" -description = "The PyPA recommended tool for installing Python packages." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "pip-tools" -version = "6.9.0" -description = "pip-tools keeps your pinned dependencies fresh." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -build = "*" -click = ">=7" -pip = ">=21.2" -setuptools = "*" -wheel = "*" - -[package.extras] -coverage = ["pytest-cov"] -testing = ["pytest", "pytest-rerunfailures", "pytest-xdist"] - -[[package]] -name = "pkgutil_resolve_name" -version = "1.3.10" -description = "Resolve a name to an object." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pre-commit" -version = "2.20.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -toml = "*" -virtualenv = ">=20.0.8" - -[[package]] -name = "prompt-toolkit" -version = "3.0.31" -description = "Library for building powerful interactive command lines in Python" -category = "dev" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -wcwidth = "*" - -[[package]] -name = "protobuf" -version = "3.20.3" -description = "Protocol Buffers" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "psutil" -version = "5.9.2" -description = "Cross-platform lib for process and system monitoring in Python." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] - -[[package]] -name = "ptyprocess" -version = "0.7.0" -description = "Run a subprocess in a pseudo terminal" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "pure-eval" -version = "0.2.2" -description = "Safely evaluate AST nodes without side effects" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -tests = ["pytest"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[[package]] -name = "pycodestyle" -version = "2.9.1" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pycparser" -version = "2.21" -description = "C parser in Python" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "pyflakes" -version = "2.5.0" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "PyGithub" -version = "1.55" -description = "Use the full Github API v3" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -deprecated = "*" -pyjwt = ">=2.0" -pynacl = ">=1.4.0" -requests = ">=2.14.0" - -[package.extras] -integrations = ["cryptography"] - -[[package]] -name = "Pygments" -version = "2.13.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pygtrie" -version = "2.5.0" -description = "A pure Python trie data structure implementation." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "pyhocon" -version = "0.3.59" -description = "HOCON parser for Python" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -pyparsing = ">=2.0,<3.0" - -[package.extras] -Duration = ["python-dateutil (>=2.8.0)"] - -[[package]] -name = "PyJWT" -version = "2.5.0" -description = "JSON Web Token implementation in Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -crypto = ["cryptography (>=3.3.1)", "types-cryptography (>=3.3.21)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.3.1)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "types-cryptography (>=3.3.21)", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] - -[[package]] -name = "pylint" -version = "2.15.3" -description = "python code static checker" -category = "dev" -optional = false -python-versions = ">=3.7.2" - -[package.dependencies] -astroid = ">=2.12.10,<=2.14.0-dev0" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = ">=0.2" -isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.8" -platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.10.1" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} - -[package.extras] -spelling = ["pyenchant (>=3.2,<4.0)"] -testutils = ["gitpython (>3)"] - -[[package]] -name = "pyluach" -version = "2.0.1" -description = "Pyluach is a Python package for manipulating Hebrew dates," -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "PyNaCl" -version = "1.5.0" -description = "Python binding to the Networking and Cryptography (NaCl) library" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = ">=1.4.1" - -[package.extras] -docs = ["sphinx (>=1.6.5)", "sphinx_rtd_theme"] -tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] - -[[package]] -name = "pyparsing" -version = "2.4.7" -description = "Python parsing module" -category = "main" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "pyrsistent" -version = "0.18.1" -description = "Persistent/Functional/Immutable data structures" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "PySide2" -version = "5.15.2.1" -description = "Python bindings for the Qt cross-platform application and UI framework" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11" - -[package.dependencies] -shiboken2 = "5.15.2.1" - -[[package]] -name = "pytest" -version = "7.1.3" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "4.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] - -[[package]] -name = "pytest-forked" -version = "1.4.0" -description = "run tests in isolated forked subprocesses" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -py = "*" -pytest = ">=3.10" - -[[package]] -name = "pytest-xdist" -version = "2.5.0" -description = "pytest xdist plugin for distributed testing and loop-on-failing modes" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -execnet = ">=1.1" -pytest = ">=6.2.0" -pytest-forked = "*" - -[package.extras] -psutil = ["psutil (>=3.0)"] -setproctitle = ["setproctitle"] -testing = ["filelock"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pytz" -version = "2022.4" -description = "World timezone definitions, modern and historical" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "pytz-deprecation-shim" -version = "0.1.0.post0" -description = "Shims to make deprecation of pytz easier" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" - -[package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""} -tzdata = {version = "*", markers = "python_version >= \"3.6\""} - -[[package]] -name = "pyupgrade" -version = "3.0.0" -description = "A tool to automatically upgrade syntax for newer versions." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -tokenize-rt = ">=3.2.0" - -[[package]] -name = "pywin32" -version = "304" -description = "Python for Window Extensions" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "pywinauto" -version = "0.6.8" -description = "A set of Python modules to automate the Microsoft Windows GUI" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -comtypes = "*" -pywin32 = "*" -six = "*" - -[[package]] -name = "PyYAML" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pyzmq" -version = "24.0.1" -description = "Python bindings for 0MQ" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = {version = "*", markers = "implementation_name == \"pypy\""} -py = {version = "*", markers = "implementation_name == \"pypy\""} - -[[package]] -name = "QtPy" -version = "2.2.1" -description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -packaging = "*" - -[package.extras] -test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] - -[[package]] -name = "requests" -version = "2.28.1" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=3.7, <4" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "Rx" -version = "3.2.0" -description = "Reactive Extensions (Rx) for Python" -category = "main" -optional = false -python-versions = ">=3.6.0" - -[[package]] -name = "schedule" -version = "1.1.0" -description = "Job scheduling for humans." -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "Send2Trash" -version = "1.8.0" -description = "Send file to trash natively under Mac OS X, Windows and Linux." -category = "main" -optional = false -python-versions = "*" - -[package.extras] -nativelib = ["pyobjc-framework-Cocoa", "pywin32"] -objc = ["pyobjc-framework-Cocoa"] -win32 = ["pywin32"] - -[[package]] -name = "setuptools" -version = "65.4.1" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "shiboken2" -version = "5.15.2.1" -description = "Python / C++ bindings helper module" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11" - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "soupsieve" -version = "2.3.2.post1" -description = "A modern CSS selector implementation for Beautiful Soup." -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "Sphinx" -version = "5.2.3" -description = "Python documentation generator" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.14,<0.20" -imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.12" -requests = ">=2.5.0" -snowballstemmer = ">=2.0" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"] -test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] - -[[package]] -name = "sphinx-autoapi" -version = "2.0.0" -description = "Sphinx API documentation generator" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -astroid = ">=2.7" -Jinja2 = "*" -PyYAML = "*" -sphinx = ">=4.0" -unidecode = "*" - -[package.extras] -docs = ["sphinx", "sphinx-rtd-theme"] -dotnet = ["sphinxcontrib-dotnetdomain"] -go = ["sphinxcontrib-golangdomain"] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "1.0.2" -description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.0" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["html5lib", "pytest"] - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -test = ["flake8", "mypy", "pytest"] - -[[package]] -name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "SQLAlchemy" -version = "1.4.41" -description = "Database Abstraction Library" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} - -[package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb_connector = ["mariadb (>=1.0.1,!=1.1.2)"] -mssql = ["pyodbc"] -mssql_pymssql = ["pymssql"] -mssql_pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql_connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql_pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql_psycopg2binary = ["psycopg2-binary"] -postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] - -[[package]] -name = "stack-data" -version = "0.5.1" -description = "Extract data from python stack frames and tracebacks for informative displays" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -asttokens = "*" -executing = "*" -pure-eval = "*" - -[package.extras] -tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] - -[[package]] -name = "tabulate" -version = "0.9.0" -description = "Pretty-print tabular data" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -widechars = ["wcwidth"] - -[[package]] -name = "tinycss2" -version = "1.1.1" -description = "A tiny CSS parser" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -webencodings = ">=0.4" - -[package.extras] -doc = ["sphinx", "sphinx_rtd_theme"] -test = ["coverage[toml]", "pytest", "pytest-cov", "pytest-flake8", "pytest-isort"] - -[[package]] -name = "tokenize-rt" -version = "5.0.0" -description = "A wrapper around the stdlib `tokenize` which roundtrips." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tomlkit" -version = "0.11.5" -description = "Style preserving TOML library" -category = "dev" -optional = false -python-versions = ">=3.6,<4.0" - -[[package]] -name = "toolz" -version = "0.12.0" -description = "List processing tools and functional utilities" -category = "main" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "tornado" -version = "6.2" -description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "dev" -optional = false -python-versions = ">= 3.7" - -[[package]] -name = "tqdm" -version = "4.64.1" -description = "Fast, Extensible Progress Meter" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -dev = ["py-make (>=0.1.0)", "twine", "wheel"] -notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] - -[[package]] -name = "traitlets" -version = "5.4.0" -description = "" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -test = ["pre-commit", "pytest"] - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tzdata" -version = "2022.4" -description = "Provider of IANA time zone data" -category = "main" -optional = false -python-versions = ">=2" - -[[package]] -name = "tzlocal" -version = "4.2" -description = "tzinfo object for the local timezone" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -pytz-deprecation-shim = "*" -tzdata = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"] -test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"] - -[[package]] -name = "Unidecode" -version = "1.3.6" -description = "ASCII transliterations of Unicode text" -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "urllib3" -version = "1.26.12" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "virtualenv" -version = "20.16.5" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -distlib = ">=0.3.5,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" - -[package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "wcwidth" -version = "0.2.5" -description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "webencodings" -version = "0.5.1" -description = "Character encoding aliases for legacy web content" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "wheel" -version = "0.37.1" -description = "A built-package format for Python" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[package.extras] -test = ["pytest (>=3.0.0)", "pytest-cov"] - -[[package]] -name = "windows-curses" -version = "2.3.0" -description = "Support for the standard curses module on Windows" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "wrapt" -version = "1.14.1" -description = "Module for decorators, wrappers and monkey patching." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "yarl" -version = "1.8.1" -description = "Yet another URL library" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" - -[[package]] -name = "zipp" -version = "3.9.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[metadata] -lock-version = "1.1" -python-versions = ">=3.8.1,<3.11" -content-hash = "b686ad04b2f56929382483e98390e5cd1d238c27a02f6b45530353f729bc0d7b" - -[metadata.files] -actions-toolkit = [ - {file = "actions-toolkit-0.1.14.tar.gz", hash = "sha256:1665aa5c609cd12900b4ac4849b880300eafb21b3e06275a5bbe30db997892fa"}, - {file = "actions_toolkit-0.1.14-py3-none-any.whl", hash = "sha256:4ec037668043b9191009029a485f0597747bd90059ff8262ccef9bff457d746a"}, -] -aiohttp = [ - {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"}, - {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"}, - {file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b"}, - {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142"}, - {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b"}, - {file = "aiohttp-3.8.3-cp310-cp310-win32.whl", hash = "sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb"}, - {file = "aiohttp-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d"}, - {file = "aiohttp-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d"}, - {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73"}, - {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34"}, - {file = "aiohttp-3.8.3-cp311-cp311-win32.whl", hash = "sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697"}, - {file = "aiohttp-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290"}, - {file = "aiohttp-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85"}, - {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d"}, - {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1"}, - {file = "aiohttp-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b"}, - {file = "aiohttp-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494"}, - {file = "aiohttp-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2"}, - {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48"}, - {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0"}, - {file = "aiohttp-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033"}, - {file = "aiohttp-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4"}, - {file = "aiohttp-3.8.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342"}, - {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6"}, - {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937"}, - {file = "aiohttp-3.8.3-cp38-cp38-win32.whl", hash = "sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76"}, - {file = "aiohttp-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba"}, - {file = "aiohttp-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa"}, - {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c"}, - {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403"}, - {file = "aiohttp-3.8.3-cp39-cp39-win32.whl", hash = "sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618"}, - {file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"}, - {file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"}, -] -aiosignal = [ - {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, - {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, -] -alabaster = [ - {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, - {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, -] -appnope = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] -astroid = [ - {file = "astroid-2.12.10-py3-none-any.whl", hash = "sha256:997e0c735df60d4a4caff27080a3afc51f9bdd693d3572a4a0b7090b645c36c5"}, - {file = "astroid-2.12.10.tar.gz", hash = "sha256:81f870105d892e73bf535da77a8261aa5bde838fa4ed12bb2f435291a098c581"}, -] -asttokens = [ - {file = "asttokens-2.0.8-py2.py3-none-any.whl", hash = "sha256:e3305297c744ae53ffa032c45dc347286165e4ffce6875dc662b205db0623d86"}, - {file = "asttokens-2.0.8.tar.gz", hash = "sha256:c61e16246ecfb2cde2958406b4c8ebc043c9e6d73aaa83c941673b35e5d3a76b"}, -] -astunparse = [ - {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, - {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"}, -] -async-timeout = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, -] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -Babel = [ - {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"}, - {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"}, -] -backcall = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] -"backports.zoneinfo" = [ - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, - {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, -] -beautifulsoup4 = [ - {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, - {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, -] -black = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, -] -bleach = [ - {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, - {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, -] -build = [ - {file = "build-0.8.0-py3-none-any.whl", hash = "sha256:19b0ed489f92ace6947698c3ca8436cb0556a66e2aa2d34cd70e2a5d27cd0437"}, - {file = "build-0.8.0.tar.gz", hash = "sha256:887a6d471c901b1a6e6574ebaeeebb45e5269a79d095fe9a8f88d6614ed2e5f0"}, -] -bump2version = [ - {file = "bump2version-1.0.1-py2.py3-none-any.whl", hash = "sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410"}, - {file = "bump2version-1.0.1.tar.gz", hash = "sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6"}, -] -certifi = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, -] -cffi = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, -] -cfgv = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -codecov = [ - {file = "codecov-2.1.12-py2.py3-none-any.whl", hash = "sha256:585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47"}, - {file = "codecov-2.1.12.tar.gz", hash = "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -comtypes = [ - {file = "comtypes-1.1.14-py2.py3-none-any.whl", hash = "sha256:7cdbe2dc65fe105eea97be04dc50ee3178747bcb64d802d7c0832416d75a87bd"}, - {file = "comtypes-1.1.14.zip", hash = "sha256:5d7caf6d3a86d51ddfc53e4548cae2dceee1b46672f8bd59679711dd01a934f2"}, -] -coverage = [ - {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, - {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, - {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, - {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, - {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, - {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, - {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, - {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, - {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, - {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, - {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, - {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, - {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, - {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, - {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, - {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, - {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, - {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, - {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, - {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, - {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, - {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, - {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, - {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, - {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, - {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, - {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, - {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, -] -cryptography = [ - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f"}, - {file = "cryptography-38.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd"}, - {file = "cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a"}, - {file = "cryptography-38.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294"}, - {file = "cryptography-38.0.1-cp36-abi3-win32.whl", hash = "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0"}, - {file = "cryptography-38.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9"}, - {file = "cryptography-38.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013"}, - {file = "cryptography-38.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a"}, - {file = "cryptography-38.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b"}, - {file = "cryptography-38.0.1.tar.gz", hash = "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7"}, -] -decorator = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] -defusedxml = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] -Deprecated = [ - {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, - {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, -] -dill = [ - {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"}, - {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"}, -] -"discord.py" = [ - {file = "discord.py-2.0.1-py3-none-any.whl", hash = "sha256:aeb186348bf011708b085b2715cf92bbb72c692eb4f59c4c0b488130cc4c4b7e"}, - {file = "discord.py-2.0.1.tar.gz", hash = "sha256:309146476e986cb8faf038cd5d604d4b3834ef15c2d34df697ce5064bf5cd779"}, -] -distlib = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, -] -docutils = [ - {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"}, - {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, -] -dunamai = [ - {file = "dunamai-1.13.1-py3-none-any.whl", hash = "sha256:f23d31fd3e7df1c16f018f4f0c408df7feda8cba9516f7c9822a29fa3ed665cd"}, - {file = "dunamai-1.13.1.tar.gz", hash = "sha256:49597bdf653bdacdeb51ec6e0f1d4d2327309376fc83e6f1d42af6e29600515f"}, -] -entrypoints = [ - {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, - {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, -] -et-xmlfile = [ - {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, - {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, -] -exchange-calendars = [ - {file = "exchange_calendars-4.2.3-py3-none-any.whl", hash = "sha256:c819bbf9a7e4ee2cb734bcdc08723f0828424b184ec7cc43f26c40e0115fb343"}, - {file = "exchange_calendars-4.2.3.tar.gz", hash = "sha256:e53a25aaeca92014ee6fc7455a3d88c4f851d2c922bb91df98a5c8ccb64d140d"}, -] -execnet = [ - {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, - {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, -] -executing = [ - {file = "executing-1.1.1-py2.py3-none-any.whl", hash = "sha256:236ea5f059a38781714a8bfba46a70fad3479c2f552abee3bbafadc57ed111b8"}, - {file = "executing-1.1.1.tar.gz", hash = "sha256:b0d7f8dcc2bac47ce6e39374397e7acecea6fdc380a6d5323e26185d70f38ea8"}, -] -fastjsonschema = [ - {file = "fastjsonschema-2.16.2-py3-none-any.whl", hash = "sha256:21f918e8d9a1a4ba9c22e09574ba72267a6762d47822db9add95f6454e51cc1c"}, - {file = "fastjsonschema-2.16.2.tar.gz", hash = "sha256:01e366f25d9047816fe3d288cbfc3e10541daf0af2044763f3d0ade42476da18"}, -] -filelock = [ - {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, - {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, -] -flake8 = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, -] -frozenlist = [ - {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"}, - {file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"}, - {file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"}, - {file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"}, - {file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"}, - {file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"}, - {file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"}, - {file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"}, - {file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"}, - {file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"}, - {file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"}, - {file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"}, - {file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"}, - {file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"}, - {file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"}, - {file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"}, - {file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"}, - {file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"}, - {file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"}, - {file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"}, - {file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"}, - {file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"}, - {file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"}, -] -greenlet = [ - {file = "greenlet-1.1.3-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:8c287ae7ac921dfde88b1c125bd9590b7ec3c900c2d3db5197f1286e144e712b"}, - {file = "greenlet-1.1.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:870a48007872d12e95a996fca3c03a64290d3ea2e61076aa35d3b253cf34cd32"}, - {file = "greenlet-1.1.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7c5227963409551ae4a6938beb70d56bf1918c554a287d3da6853526212fbe0a"}, - {file = "greenlet-1.1.3-cp27-cp27m-win32.whl", hash = "sha256:9fae214f6c43cd47f7bef98c56919b9222481e833be2915f6857a1e9e8a15318"}, - {file = "greenlet-1.1.3-cp27-cp27m-win_amd64.whl", hash = "sha256:de431765bd5fe62119e0bc6bc6e7b17ac53017ae1782acf88fcf6b7eae475a49"}, - {file = "greenlet-1.1.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:510c3b15587afce9800198b4b142202b323bf4b4b5f9d6c79cb9a35e5e3c30d2"}, - {file = "greenlet-1.1.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9951dcbd37850da32b2cb6e391f621c1ee456191c6ae5528af4a34afe357c30e"}, - {file = "greenlet-1.1.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:07c58e169bbe1e87b8bbf15a5c1b779a7616df9fd3e61cadc9d691740015b4f8"}, - {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df02fdec0c533301497acb0bc0f27f479a3a63dcdc3a099ae33a902857f07477"}, - {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c88e134d51d5e82315a7c32b914a58751b7353eb5268dbd02eabf020b4c4700"}, - {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b41d19c0cfe5c259fe6c539fd75051cd39a5d33d05482f885faf43f7f5e7d26"}, - {file = "greenlet-1.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:6f5d4b2280ceea76c55c893827961ed0a6eadd5a584a7c4e6e6dd7bc10dfdd96"}, - {file = "greenlet-1.1.3-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:184416e481295832350a4bf731ba619a92f5689bf5d0fa4341e98b98b1265bd7"}, - {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd0404d154084a371e6d2bafc787201612a1359c2dee688ae334f9118aa0bf47"}, - {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a43bbfa9b6cfdfaeefbd91038dde65ea2c421dc387ed171613df340650874f2"}, - {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce5b64dfe8d0cca407d88b0ee619d80d4215a2612c1af8c98a92180e7109f4b5"}, - {file = "greenlet-1.1.3-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:903fa5716b8fbb21019268b44f73f3748c41d1a30d71b4a49c84b642c2fed5fa"}, - {file = "greenlet-1.1.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0118817c9341ef2b0f75f5af79ac377e4da6ff637e5ee4ac91802c0e379dadb4"}, - {file = "greenlet-1.1.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:466ce0928e33421ee84ae04c4ac6f253a3a3e6b8d600a79bd43fd4403e0a7a76"}, - {file = "greenlet-1.1.3-cp35-cp35m-win32.whl", hash = "sha256:65ad1a7a463a2a6f863661329a944a5802c7129f7ad33583dcc11069c17e622c"}, - {file = "greenlet-1.1.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7532a46505470be30cbf1dbadb20379fb481244f1ca54207d7df3bf0bbab6a20"}, - {file = "greenlet-1.1.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:caff52cb5cd7626872d9696aee5b794abe172804beb7db52eed1fd5824b63910"}, - {file = "greenlet-1.1.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:db41f3845eb579b544c962864cce2c2a0257fe30f0f1e18e51b1e8cbb4e0ac6d"}, - {file = "greenlet-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8533f5111704d75de3139bf0b8136d3a6c1642c55c067866fa0a51c2155ee33"}, - {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537e4baf0db67f382eb29255a03154fcd4984638303ff9baaa738b10371fa57"}, - {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8bfd36f368efe0ab2a6aa3db7f14598aac454b06849fb633b762ddbede1db90"}, - {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0877a9a2129a2c56a2eae2da016743db7d9d6a05d5e1c198f1b7808c602a30e"}, - {file = "greenlet-1.1.3-cp36-cp36m-win32.whl", hash = "sha256:88b04e12c9b041a1e0bcb886fec709c488192638a9a7a3677513ac6ba81d8e79"}, - {file = "greenlet-1.1.3-cp36-cp36m-win_amd64.whl", hash = "sha256:4f166b4aca8d7d489e82d74627a7069ab34211ef5ebb57c300ec4b9337b60fc0"}, - {file = "greenlet-1.1.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cd16a89efe3a003029c87ff19e9fba635864e064da646bc749fc1908a4af18f3"}, - {file = "greenlet-1.1.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5b756e6730ea59b2745072e28ad27f4c837084688e6a6b3633c8b1e509e6ae0e"}, - {file = "greenlet-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:9b2f7d0408ddeb8ea1fd43d3db79a8cefaccadd2a812f021333b338ed6b10aba"}, - {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44b4817c34c9272c65550b788913620f1fdc80362b209bc9d7dd2f40d8793080"}, - {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d58a5a71c4c37354f9e0c24c9c8321f0185f6945ef027460b809f4bb474bfe41"}, - {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dd51d2650e70c6c4af37f454737bf4a11e568945b27f74b471e8e2a9fd21268"}, - {file = "greenlet-1.1.3-cp37-cp37m-win32.whl", hash = "sha256:048d2bed76c2aa6de7af500ae0ea51dd2267aec0e0f2a436981159053d0bc7cc"}, - {file = "greenlet-1.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:77e41db75f9958f2083e03e9dd39da12247b3430c92267df3af77c83d8ff9eed"}, - {file = "greenlet-1.1.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:1626185d938d7381631e48e6f7713e8d4b964be246073e1a1d15c2f061ac9f08"}, - {file = "greenlet-1.1.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1ec2779774d8e42ed0440cf8bc55540175187e8e934f2be25199bf4ed948cd9e"}, - {file = "greenlet-1.1.3-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f2f908239b7098799b8845e5936c2ccb91d8c2323be02e82f8dcb4a80dcf4a25"}, - {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b181e9aa6cb2f5ec0cacc8cee6e5a3093416c841ba32c185c30c160487f0380"}, - {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2cf45e339cabea16c07586306a31cfcc5a3b5e1626d365714d283732afed6809"}, - {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6200a11f003ec26815f7e3d2ded01b43a3810be3528dd760d2f1fa777490c3cd"}, - {file = "greenlet-1.1.3-cp38-cp38-win32.whl", hash = "sha256:db5b25265010a1b3dca6a174a443a0ed4c4ab12d5e2883a11c97d6e6d59b12f9"}, - {file = "greenlet-1.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:095a980288fe05adf3d002fbb180c99bdcf0f930e220aa66fcd56e7914a38202"}, - {file = "greenlet-1.1.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:cbc1eb55342cbac8f7ec159088d54e2cfdd5ddf61c87b8bbe682d113789331b2"}, - {file = "greenlet-1.1.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:694ffa7144fa5cc526c8f4512665003a39fa09ef00d19bbca5c8d3406db72fbe"}, - {file = "greenlet-1.1.3-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:aa741c1a8a8cc25eb3a3a01a62bdb5095a773d8c6a86470bde7f607a447e7905"}, - {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3a669f11289a8995d24fbfc0e63f8289dd03c9aaa0cc8f1eab31d18ca61a382"}, - {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76a53bfa10b367ee734b95988bd82a9a5f0038a25030f9f23bbbc005010ca600"}, - {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fb0aa7f6996879551fd67461d5d3ab0c3c0245da98be90c89fcb7a18d437403"}, - {file = "greenlet-1.1.3-cp39-cp39-win32.whl", hash = "sha256:5fbe1ab72b998ca77ceabbae63a9b2e2dc2d963f4299b9b278252ddba142d3f1"}, - {file = "greenlet-1.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:ffe73f9e7aea404722058405ff24041e59d31ca23d1da0895af48050a07b6932"}, - {file = "greenlet-1.1.3.tar.gz", hash = "sha256:bcb6c6dd1d6be6d38d6db283747d07fda089ff8c559a835236560a4410340455"}, -] -grpcio = [ - {file = "grpcio-1.48.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:665141b3a97b7d22978c8d2ba0c0af7f67bd6d7a56889c5c0aa715d04009b518"}, - {file = "grpcio-1.48.2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:199526758f6f8d35a596c610f33ea76faae65ec175dc109e8481ea3404d8527c"}, - {file = "grpcio-1.48.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:3d3225d477663c27b9051546a32551babd1ccb80192905e08340264deccc975b"}, - {file = "grpcio-1.48.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abee7dd82443b2cd128004e053b263a6d7256d570df80956a974634b8c5bc121"}, - {file = "grpcio-1.48.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dc08baa1b28749e90428aaa16e038e8c389d8ccb843ddc0dc8b95231640b432"}, - {file = "grpcio-1.48.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:110028e0b9c346230ae69b8a6d8b25d4d43bfd37bda61a8ec46486da1e781dcb"}, - {file = "grpcio-1.48.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6affa7e685edbb7421f942296eb618359362e89e641bcf46779c6ec7b944d275"}, - {file = "grpcio-1.48.2-cp310-cp310-win32.whl", hash = "sha256:f6afd1f4b5e0ec320fb2b027a646944fee8b58ba00fb43d081968f77d1a6e925"}, - {file = "grpcio-1.48.2-cp310-cp310-win_amd64.whl", hash = "sha256:b8ec07dcc1cbd77b8c09dfc0ce6274920cb7b09cc04013110971d95d8bcc0bbf"}, - {file = "grpcio-1.48.2-cp36-cp36m-linux_armv7l.whl", hash = "sha256:550b08dfa938e30ffbc1652193cf2877906aa6242d6ba9f61318dc87fcecee63"}, - {file = "grpcio-1.48.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:c19d6f337860f382ceaa35c5acab439d84c5ffaa8baba36df1f83ab6b9ac4bd3"}, - {file = "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:e69a5907a2a4cf0011ff46205b6bff8f56b8391436acc3c66b70ce8519578d7e"}, - {file = "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:894c5f02c25c83c2320310521a82978b4e252ee18b99a5c4c564d73daeb5c1de"}, - {file = "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47ace91631176efa575c7a34d5004286288f1af1e9de2ff380d1433f241aeed4"}, - {file = "grpcio-1.48.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f1d2cd5b1adecbcffee4ad6613f100e0b583ae2e253d2f8f685e7770ec72d622"}, - {file = "grpcio-1.48.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:f5697e4ab90a41a6a1202c1a3ec268a0d69f1cd127a4940d2b2521a0fbc1277b"}, - {file = "grpcio-1.48.2-cp36-cp36m-win32.whl", hash = "sha256:cebeed160466a1e254eb75e7e1bbeeb1359c50b33a1b8f3b2241a8b8dc9bd216"}, - {file = "grpcio-1.48.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0802b080b6b8603a065e505ce83190b6a06229b9a74d0a1681175271ac84fe12"}, - {file = "grpcio-1.48.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:855c125e8cd1c3ab09a239689c940d26c30680edf2edf87c3c1543bd8633cc8f"}, - {file = "grpcio-1.48.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5571cb828d694b34a7c75484722803e13a2f5e4760e47ae32fb077c83d0c9b2c"}, - {file = "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:2f185b8c5130663c455f6542906ce99f046608e94950c8b354aa22462c202c2d"}, - {file = "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7b1a3a75c34ab39c9df73aa9fecc519dc1035e588a41af19f39b1298a283a57"}, - {file = "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7ec6b04875a5065d04ad86cd2678ca6431dec868c01d731b8233f3de155bfdf"}, - {file = "grpcio-1.48.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e48595440dc86e13245aec7c096238db12b659e5ae6078aecf99d66befb77678"}, - {file = "grpcio-1.48.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ec2dd9f7ab0c809af6b2c65ed31c3cbef2ca9695f7f4d49866ec4707e7836890"}, - {file = "grpcio-1.48.2-cp37-cp37m-win32.whl", hash = "sha256:1fea4cb4368dd0467eb2d208e2d5e3c4f0be28fe33965d45ac9e1d562be67a8c"}, - {file = "grpcio-1.48.2-cp37-cp37m-win_amd64.whl", hash = "sha256:0bfb637344442b273b698ff425d735a5d806ca8715f988875ad669277fb9b1e6"}, - {file = "grpcio-1.48.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:c92b5ef64cd5a0c6aea82dd6862fdb8a1562510d537ea3c356a7fe60db7021af"}, - {file = "grpcio-1.48.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:2bb1df2920a4968f0c09041b49e591df96f2e6f801f15eed3821c1f16a12f1a8"}, - {file = "grpcio-1.48.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:3f52ef5ba7a8bc334daa87675838d6dafda7d8a116a72b567b8351e561ace498"}, - {file = "grpcio-1.48.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c3b69f8efb214a54f48e8dd1e235a4d8d22fa985f32a9b2844373993c5a605"}, - {file = "grpcio-1.48.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a760ef87fde9a8f2761c7ad8ccf617fc590547ed743a9207fe7e367496164c60"}, - {file = "grpcio-1.48.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1e2dc213fe71566efbf9a5d704c665ff4b1760a88d37f8533b19ca92776070c9"}, - {file = "grpcio-1.48.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3463256399158e9abf115620994e968db8f003224c36bda0d14570eab8a44cfc"}, - {file = "grpcio-1.48.2-cp38-cp38-win32.whl", hash = "sha256:dc00681d546cae66e9d54451f650fe140f9e1aca2dc4f8c9686cfaa4dd5d680b"}, - {file = "grpcio-1.48.2-cp38-cp38-win_amd64.whl", hash = "sha256:b8768daa636e0fa48fec75517bea65ce8fdaca0066dc411fc0a2290d92032f91"}, - {file = "grpcio-1.48.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:104b555e1cb2e0614f05c1def24eb8bb06f1277460058aa0f9c9e6a1018716da"}, - {file = "grpcio-1.48.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:8d130f666463e4d09a63ff033a6c5cd032867fd51a0db4660c18106aa352be3a"}, - {file = "grpcio-1.48.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5792943481d4270b3e9a4700af0eea86e7183f4d3c250a46e0b357949cc09411"}, - {file = "grpcio-1.48.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26ed6d07f91ce8aeb4697b7e71d930355282ec80acb7a488f4030a3a75c2f7a8"}, - {file = "grpcio-1.48.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c0d0995a0cd8c7198cb49b8ce98b4936c5a70109f9246c58e69c898e4f7329"}, - {file = "grpcio-1.48.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b860e13c112bb9cb44007ef02853a19397d915b31c42dfa18570448bdc0a6245"}, - {file = "grpcio-1.48.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6f693da8ffd2486c354c90ba5a8ca0f4c50bfb8853495501884cadc152551360"}, - {file = "grpcio-1.48.2-cp39-cp39-win32.whl", hash = "sha256:2d99fb56c7e836f165828719c3695d3d27ac70b103ab52226f7a7c237e4a3928"}, - {file = "grpcio-1.48.2-cp39-cp39-win_amd64.whl", hash = "sha256:514392a30a275f4f719c2e05ea969c239e5f03eec4a25965852c7582073d8b94"}, - {file = "grpcio-1.48.2.tar.gz", hash = "sha256:90e5da224c6b9b23658adf6f36de6f435ef7dbcc9c5c12330314d70d6f8de1f7"}, -] -grpcio-tools = [ - {file = "grpcio-tools-1.48.2.tar.gz", hash = "sha256:8902a035708555cddbd61b5467cea127484362decc52de03f061a1a520fe90cd"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:92acc3e10ba2b0dcb90a88ae9fe1cc0ffba6868545207e4ff20ca95284f8e3c9"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e5bb396d63495667d4df42e506eed9d74fc9a51c99c173c04395fe7604c848f1"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:84a84d601a238572d049d3108e04fe4c206536e81076d56e623bd525a1b38def"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70564521e86a0de35ea9ac6daecff10cb46860aec469af65869974807ce8e98b"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbbe63f6190187de5946891941629912ac8196701ed2253fa91624a397822ec"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae56f133b05b7e5d780ef7e032dd762adad7f3dc8f64adb43ff5bfabd659f435"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0feb4f2b777fa6377e977faa89c26359d4f31953de15e035505b92f41aa6906"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-win32.whl", hash = "sha256:80f450272316ca0924545f488c8492649ca3aeb7044d4bf59c426dcdee527f7c"}, - {file = "grpcio_tools-1.48.2-cp310-cp310-win_amd64.whl", hash = "sha256:21ff50e321736eba22210bf9b94e05391a9ac345f26e7df16333dc75d63e74fb"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-linux_armv7l.whl", hash = "sha256:d598ccde6338b2cfbb3124f34c95f03394209013f9b1ed4a5360a736853b1c27"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:a43d26714933f23de93ea0bf9c86c66a6ede709b8ca32e357f9e2181703e64ae"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:55fdebc73fb580717656b1bafa4f8eca448726a7aa22726a6c0a7895d2f0f088"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8588819b22d0de3aa1951e1991cc3e4b9aa105eecf6e3e24eb0a2fc8ab958b3e"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9771d4d317dca029dfaca7ec9282d8afe731c18bc536ece37fd39b8a974cc331"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d886a9e052a038642b3af5d18e6f2085d1656d9788e202dc23258cf3a751e7ca"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d77e8b1613876e0d8fd17709509d4ceba13492816426bd156f7e88a4c47e7158"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-win32.whl", hash = "sha256:dcaaecdd5e847de5c1d533ea91522bf56c9e6b2dc98cdc0d45f0a1c26e846ea2"}, - {file = "grpcio_tools-1.48.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0119aabd9ceedfdf41b56b9fdc8284dd85a7f589d087f2694d743f346a368556"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:189be2a9b672300ca6845d94016bdacc052fdbe9d1ae9e85344425efae2ff8ef"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:9443f5c30bac449237c3cf99da125f8d6e6c01e17972bc683ee73b75dea95573"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:e0403e095b343431195db1305248b50019ad55d3dd310254431af87e14ef83a2"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5410d6b601d1404835e34466bd8aee37213489b36ee1aad2276366e265ff29d4"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51be91b7c7056ff9ee48b1eccd4a2840b0126230803a5e09dfc082a5b16a91c1"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:516eedd5eb7af6326050bc2cfceb3a977b9cc1144f283c43cc4956905285c912"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d18599ab572b2f15a8f3db49503272d1bb4fcabb4b4d1214ef03aca1816b20a0"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-win32.whl", hash = "sha256:d18ef2adc05a8ef9e58ac46357f6d4ce7e43e077c7eda0a4425773461f9d0e6e"}, - {file = "grpcio_tools-1.48.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d9753944e5a6b6b78b76ce9d2ae0fe3f748008c1849deb7fadcb64489d6553b"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:3c8749dca04a8d302862ceeb1dfbdd071ee13b281395975f24405a347e5baa57"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:7307dd2408b82ea545ae63502ec03036b025f449568556ea9a056e06129a7a4e"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:072234859f6069dc43a6be8ad6b7d682f4ba1dc2e2db2ebf5c75f62eee0f6dfb"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cc298fbfe584de8876a85355efbcf796dfbcfac5948c9560f5df82e79336e2a"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f75973a42c710999acd419968bc79f00327e03e855bbe82c6529e003e49af660"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f766050e491d0b3203b6b85638015f543816a2eb7d089fc04e86e00f6de0e31d"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8e0d74403484eb77e8df2566a64b8b0b484b5c87903678c381634dd72f252d5e"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-win32.whl", hash = "sha256:cb75bac0cd43858cb759ef103fe68f8c540cb58b63dda127e710228fec3007b8"}, - {file = "grpcio_tools-1.48.2-cp38-cp38-win_amd64.whl", hash = "sha256:cabc8b0905cedbc3b2b7b2856334fa35cce3d4bc79ae241cacd8cca8940a5c85"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:e712a6d00606ad19abdeae852a7e521d6f6d0dcea843708fecf3a38be16a851e"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:e7e7668f89fd598c5469bb58e16bfd12b511d9947ccc75aec94da31f62bc3758"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:a415fbec67d4ff7efe88794cbe00cf548d0f0a5484cceffe0a0c89d47694c491"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d96e96ae7361aa51c9cd9c73b677b51f691f98df6086860fcc3c45852d96b0b0"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e20d7885a40e68a2bda92908acbabcdf3c14dd386c3845de73ba139e9df1f132"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8a5614251c46da07549e24f417cf989710250385e9d80deeafc53a0ee7df6325"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ace0035766fe01a1b096aa050be9f0a9f98402317e7aeff8bfe55349be32a407"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-win32.whl", hash = "sha256:4fa4300b1be59b046492ed3c5fdb59760bc6433f44c08f50de900f9552ec7461"}, - {file = "grpcio_tools-1.48.2-cp39-cp39-win_amd64.whl", hash = "sha256:0fb6c1c1e56eb26b224adc028a4204b6ad0f8b292efa28067dff273bbc8b27c4"}, -] -identify = [ - {file = "identify-2.5.6-py2.py3-none-any.whl", hash = "sha256:b276db7ec52d7e89f5bc4653380e33054ddc803d25875952ad90b0f012cbcdaa"}, - {file = "identify-2.5.6.tar.gz", hash = "sha256:6c32dbd747aa4ceee1df33f25fed0b0f6e0d65721b15bd151307ff7056d50245"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -imagesize = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] -importlib-metadata = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, -] -importlib-resources = [ - {file = "importlib_resources-5.10.0-py3-none-any.whl", hash = "sha256:ee17ec648f85480d523596ce49eae8ead87d5631ae1551f913c0100b5edd3437"}, - {file = "importlib_resources-5.10.0.tar.gz", hash = "sha256:c01b1b94210d9849f286b86bb51bcea7cd56dde0600d8db721d7b81330711668"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -ipython = [ - {file = "ipython-8.5.0-py3-none-any.whl", hash = "sha256:6f090e29ab8ef8643e521763a4f1f39dc3914db643122b1e9d3328ff2e43ada2"}, - {file = "ipython-8.5.0.tar.gz", hash = "sha256:097bdf5cd87576fd066179c9f7f208004f7a6864ee1b20f37d346c0bcb099f84"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -jedi = [ - {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, - {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, -] -Jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -jsonschema = [ - {file = "jsonschema-4.16.0-py3-none-any.whl", hash = "sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"}, - {file = "jsonschema-4.16.0.tar.gz", hash = "sha256:165059f076eff6971bae5b742fc029a7b4ef3f9bcf04c14e4776a7605de14b23"}, -] -jupyter-client = [ - {file = "jupyter_client-7.3.5-py3-none-any.whl", hash = "sha256:b33222bdc9dd1714228bd286af006533a0abe2bbc093e8f3d29dc0b91bdc2be4"}, - {file = "jupyter_client-7.3.5.tar.gz", hash = "sha256:3c58466a1b8d55dba0bf3ce0834e4f5b7760baf98d1d73db0add6f19de9ecd1d"}, -] -jupyter-core = [ - {file = "jupyter_core-4.11.1-py3-none-any.whl", hash = "sha256:715e22bb6cc7db3718fddfac1f69f1c7e899ca00e42bdfd4bf3705452b9fd84a"}, - {file = "jupyter_core-4.11.1.tar.gz", hash = "sha256:2e5f244d44894c4154d06aeae3419dd7f1b0ef4494dc5584929b398c61cfd314"}, -] -jupyterlab-pygments = [ - {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"}, - {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"}, -] -korean-lunar-calendar = [ - {file = "korean_lunar_calendar-0.3.1-py3-none-any.whl", hash = "sha256:392757135c492c4f42a604e6038042953c35c6f449dda5f27e3f86a7f9c943e5"}, - {file = "korean_lunar_calendar-0.3.1.tar.gz", hash = "sha256:eb2c485124a061016926bdea6d89efdf9b9fdbf16db55895b6cf1e5bec17b857"}, -] -lazy-object-proxy = [ - {file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"}, - {file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"}, - {file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"}, - {file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"}, - {file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"}, - {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, - {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, -] -lxml = [ - {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, - {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, - {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, - {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, - {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, - {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, - {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, - {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, - {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, - {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, - {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, - {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, - {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, - {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, - {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, - {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, - {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, - {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, - {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, - {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, - {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, -] -MarkupSafe = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, -] -matplotlib-inline = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, -] -mccabe = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] -mistune = [ - {file = "mistune-2.0.4-py2.py3-none-any.whl", hash = "sha256:182cc5ee6f8ed1b807de6b7bb50155df7b66495412836b9a74c8fbdfc75fe36d"}, - {file = "mistune-2.0.4.tar.gz", hash = "sha256:9ee0a66053e2267aba772c71e06891fa8f1af6d4b01d5e84e267b4570d4d9808"}, -] -multidict = [ - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, - {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, - {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, - {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, - {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, - {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, - {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, - {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, - {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, - {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, - {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, - {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, - {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, - {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, - {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, - {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, - {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, - {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, - {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, - {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, - {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, - {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, -] -mypy = [ - {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, - {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, - {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, - {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, - {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, - {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, - {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, - {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, - {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, - {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, - {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, - {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, - {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, - {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, - {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, - {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, - {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, - {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, - {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, - {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -nbclient = [ - {file = "nbclient-0.7.0-py3-none-any.whl", hash = "sha256:434c91385cf3e53084185334d675a0d33c615108b391e260915d1aa8e86661b8"}, - {file = "nbclient-0.7.0.tar.gz", hash = "sha256:a1d844efd6da9bc39d2209bf996dbd8e07bf0f36b796edfabaa8f8a9ab77c3aa"}, -] -nbconvert = [ - {file = "nbconvert-7.2.1-py3-none-any.whl", hash = "sha256:50a54366ab53da20e82668818b7b2f3f7b85c0bcd46ec8e18836f12b39180dfa"}, - {file = "nbconvert-7.2.1.tar.gz", hash = "sha256:1e180801205ad831b6e2480c5a03307dfb6327fa5b2f9b156d6fed45f9700686"}, -] -nbformat = [ - {file = "nbformat-5.6.1-py3-none-any.whl", hash = "sha256:9c071f0f615c1b0f4f9bf6745ecfd3294fc02daf279a05c76004c901e9dc5893"}, - {file = "nbformat-5.6.1.tar.gz", hash = "sha256:146b5b9969391387c2089256359f5da7c718b1d8a88ba814320273ea410e646e"}, -] -nbsphinx = [ - {file = "nbsphinx-0.8.9-py3-none-any.whl", hash = "sha256:a7d743762249ee6bac3350a91eb3717a6e1c75f239f2c2a85491f9aca5a63be1"}, - {file = "nbsphinx-0.8.9.tar.gz", hash = "sha256:4ade86b2a41f8f41efd3ea99dae84c3368fe8ba3f837d50c8815ce9424c5994f"}, -] -nest-asyncio = [ - {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"}, - {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"}, -] -nodeenv = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] -numpy = [ - {file = "numpy-1.23.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9f707b5bb73bf277d812ded9896f9512a43edff72712f31667d0a8c2f8e71ee"}, - {file = "numpy-1.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffcf105ecdd9396e05a8e58e81faaaf34d3f9875f137c7372450baa5d77c9a54"}, - {file = "numpy-1.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ea3f98a0ffce3f8f57675eb9119f3f4edb81888b6874bc1953f91e0b1d4f440"}, - {file = "numpy-1.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004f0efcb2fe1c0bd6ae1fcfc69cc8b6bf2407e0f18be308612007a0762b4089"}, - {file = "numpy-1.23.3-cp310-cp310-win32.whl", hash = "sha256:98dcbc02e39b1658dc4b4508442a560fe3ca5ca0d989f0df062534e5ca3a5c1a"}, - {file = "numpy-1.23.3-cp310-cp310-win_amd64.whl", hash = "sha256:39a664e3d26ea854211867d20ebcc8023257c1800ae89773cbba9f9e97bae036"}, - {file = "numpy-1.23.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1f27b5322ac4067e67c8f9378b41c746d8feac8bdd0e0ffede5324667b8a075c"}, - {file = "numpy-1.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ad3ec9a748a8943e6eb4358201f7e1c12ede35f510b1a2221b70af4bb64295c"}, - {file = "numpy-1.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdc9febce3e68b697d931941b263c59e0c74e8f18861f4064c1f712562903411"}, - {file = "numpy-1.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:301c00cf5e60e08e04d842fc47df641d4a181e651c7135c50dc2762ffe293dbd"}, - {file = "numpy-1.23.3-cp311-cp311-win32.whl", hash = "sha256:7cd1328e5bdf0dee621912f5833648e2daca72e3839ec1d6695e91089625f0b4"}, - {file = "numpy-1.23.3-cp311-cp311-win_amd64.whl", hash = "sha256:8355fc10fd33a5a70981a5b8a0de51d10af3688d7a9e4a34fcc8fa0d7467bb7f"}, - {file = "numpy-1.23.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc6e8da415f359b578b00bcfb1d08411c96e9a97f9e6c7adada554a0812a6cc6"}, - {file = "numpy-1.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:22d43376ee0acd547f3149b9ec12eec2f0ca4a6ab2f61753c5b29bb3e795ac4d"}, - {file = "numpy-1.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a64403f634e5ffdcd85e0b12c08f04b3080d3e840aef118721021f9b48fc1460"}, - {file = "numpy-1.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd9d3abe5774404becdb0748178b48a218f1d8c44e0375475732211ea47c67e"}, - {file = "numpy-1.23.3-cp38-cp38-win32.whl", hash = "sha256:f8c02ec3c4c4fcb718fdf89a6c6f709b14949408e8cf2a2be5bfa9c49548fd85"}, - {file = "numpy-1.23.3-cp38-cp38-win_amd64.whl", hash = "sha256:e868b0389c5ccfc092031a861d4e158ea164d8b7fdbb10e3b5689b4fc6498df6"}, - {file = "numpy-1.23.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09f6b7bdffe57fc61d869a22f506049825d707b288039d30f26a0d0d8ea05164"}, - {file = "numpy-1.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c79d7cf86d049d0c5089231a5bcd31edb03555bd93d81a16870aa98c6cfb79d"}, - {file = "numpy-1.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5d5420053bbb3dd64c30e58f9363d7a9c27444c3648e61460c1237f9ec3fa14"}, - {file = "numpy-1.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5422d6a1ea9b15577a9432e26608c73a78faf0b9039437b075cf322c92e98e7"}, - {file = "numpy-1.23.3-cp39-cp39-win32.whl", hash = "sha256:c1ba66c48b19cc9c2975c0d354f24058888cdc674bebadceb3cdc9ec403fb5d1"}, - {file = "numpy-1.23.3-cp39-cp39-win_amd64.whl", hash = "sha256:78a63d2df1d947bd9d1b11d35564c2f9e4b57898aae4626638056ec1a231c40c"}, - {file = "numpy-1.23.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:17c0e467ade9bda685d5ac7f5fa729d8d3e76b23195471adae2d6a6941bd2c18"}, - {file = "numpy-1.23.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91b8d6768a75247026e951dce3b2aac79dc7e78622fc148329135ba189813584"}, - {file = "numpy-1.23.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:94c15ca4e52671a59219146ff584488907b1f9b3fc232622b47e2cf832e94fb8"}, - {file = "numpy-1.23.3.tar.gz", hash = "sha256:51bf49c0cd1d52be0a240aa66f3458afc4b95d8993d2d04f0d91fa60c10af6cd"}, -] -openpyxl = [ - {file = "openpyxl-3.0.10-py2.py3-none-any.whl", hash = "sha256:0ab6d25d01799f97a9464630abacbb34aafecdcaa0ef3cba6d6b3499867d0355"}, - {file = "openpyxl-3.0.10.tar.gz", hash = "sha256:e47805627aebcf860edb4edf7987b1309c1b3632f3750538ed962bbcc3bd7449"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pandas = [ - {file = "pandas-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0d8d7433d19bfa33f11c92ad9997f15a902bda4f5ad3a4814a21d2e910894484"}, - {file = "pandas-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cc47f2ebaa20ef96ae72ee082f9e101b3dfbf74f0e62c7a12c0b075a683f03c"}, - {file = "pandas-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e8e5edf97d8793f51d258c07c629bd49d271d536ce15d66ac00ceda5c150eb3"}, - {file = "pandas-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41aec9f87455306496d4486df07c1b98c15569c714be2dd552a6124cd9fda88f"}, - {file = "pandas-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c76f1d104844c5360c21d2ef0e1a8b2ccf8b8ebb40788475e255b9462e32b2be"}, - {file = "pandas-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:1642fc6138b4e45d57a12c1b464a01a6d868c0148996af23f72dde8d12486bbc"}, - {file = "pandas-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:171cef540bfcec52257077816a4dbbac152acdb8236ba11d3196ae02bf0959d8"}, - {file = "pandas-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a68a9b9754efff364b0c5ee5b0f18e15ca640c01afe605d12ba8b239ca304d6b"}, - {file = "pandas-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:86d87279ebc5bc20848b4ceb619073490037323f80f515e0ec891c80abad958a"}, - {file = "pandas-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:207d63ac851e60ec57458814613ef4b3b6a5e9f0b33c57623ba2bf8126c311f8"}, - {file = "pandas-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e252a9e49b233ff96e2815c67c29702ac3a062098d80a170c506dff3470fd060"}, - {file = "pandas-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:de34636e2dc04e8ac2136a8d3c2051fd56ebe9fd6cd185581259330649e73ca9"}, - {file = "pandas-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1d34b1f43d9e3f4aea056ba251f6e9b143055ebe101ed04c847b41bb0bb4a989"}, - {file = "pandas-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b82ccc7b093e0a93f8dffd97a542646a3e026817140e2c01266aaef5fdde11b"}, - {file = "pandas-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e30a31039574d96f3d683df34ccb50bb435426ad65793e42a613786901f6761"}, - {file = "pandas-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62e61003411382e20d7c2aec1ee8d7c86c8b9cf46290993dd8a0a3be44daeb38"}, - {file = "pandas-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc987f7717e53d372f586323fff441263204128a1ead053c1b98d7288f836ac9"}, - {file = "pandas-1.5.0-cp38-cp38-win32.whl", hash = "sha256:e178ce2d7e3b934cf8d01dc2d48d04d67cb0abfaffdcc8aa6271fd5a436f39c8"}, - {file = "pandas-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:33a9d9e21ab2d91e2ab6e83598419ea6a664efd4c639606b299aae8097c1c94f"}, - {file = "pandas-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:73844e247a7b7dac2daa9df7339ecf1fcf1dfb8cbfd11e3ffe9819ae6c31c515"}, - {file = "pandas-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e9c5049333c5bebf993033f4bf807d163e30e8fada06e1da7fa9db86e2392009"}, - {file = "pandas-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85a516a7f6723ca1528f03f7851fa8d0360d1d6121cf15128b290cf79b8a7f6a"}, - {file = "pandas-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:947ed9f896ee61adbe61829a7ae1ade493c5a28c66366ec1de85c0642009faac"}, - {file = "pandas-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7f38d91f21937fe2bec9449570d7bf36ad7136227ef43b321194ec249e2149d"}, - {file = "pandas-1.5.0-cp39-cp39-win32.whl", hash = "sha256:2504c032f221ef9e4a289f5e46a42b76f5e087ecb67d62e342ccbba95a32a488"}, - {file = "pandas-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a4fc04838615bf0a8d3a03ed68197f358054f0df61f390bcc64fbe39e3d71ec"}, - {file = "pandas-1.5.0.tar.gz", hash = "sha256:3ee61b881d2f64dd90c356eb4a4a4de75376586cd3c9341c6c0fcaae18d52977"}, -] -pandocfilters = [ - {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"}, - {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"}, -] -parso = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, -] -pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] -pep517 = [ - {file = "pep517-0.13.0-py3-none-any.whl", hash = "sha256:4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b"}, - {file = "pep517-0.13.0.tar.gz", hash = "sha256:ae69927c5c172be1add9203726d4b84cf3ebad1edcd5f71fcdc746e66e829f59"}, -] -pexpect = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, -] -pickleshare = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] -pip = [ - {file = "pip-22.2.2-py3-none-any.whl", hash = "sha256:b61a374b5bc40a6e982426aede40c9b5a08ff20e640f5b56977f4f91fed1e39a"}, - {file = "pip-22.2.2.tar.gz", hash = "sha256:3fd1929db052f056d7a998439176d3333fa1b3f6c1ad881de1885c0717608a4b"}, -] -pip-tools = [ - {file = "pip-tools-6.9.0.tar.gz", hash = "sha256:b4762359978fd81a2b4b666e6dca15266bdc65680d06900c4da34243f35e4b5d"}, - {file = "pip_tools-6.9.0-py3-none-any.whl", hash = "sha256:16ea0ced6a1d8a7dfbd5e14d5bf659acffa63f3efd0702233dc685f066c00a6b"}, -] -pkgutil_resolve_name = [ - {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, - {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -pre-commit = [ - {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, - {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, -] -prompt-toolkit = [ - {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"}, - {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"}, -] -protobuf = [ - {file = "protobuf-3.20.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99"}, - {file = "protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e"}, - {file = "protobuf-3.20.3-cp310-cp310-win32.whl", hash = "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c"}, - {file = "protobuf-3.20.3-cp310-cp310-win_amd64.whl", hash = "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7"}, - {file = "protobuf-3.20.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469"}, - {file = "protobuf-3.20.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4"}, - {file = "protobuf-3.20.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4"}, - {file = "protobuf-3.20.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454"}, - {file = "protobuf-3.20.3-cp37-cp37m-win32.whl", hash = "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905"}, - {file = "protobuf-3.20.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c"}, - {file = "protobuf-3.20.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7"}, - {file = "protobuf-3.20.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee"}, - {file = "protobuf-3.20.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050"}, - {file = "protobuf-3.20.3-cp38-cp38-win32.whl", hash = "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86"}, - {file = "protobuf-3.20.3-cp38-cp38-win_amd64.whl", hash = "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9"}, - {file = "protobuf-3.20.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b"}, - {file = "protobuf-3.20.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b"}, - {file = "protobuf-3.20.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402"}, - {file = "protobuf-3.20.3-cp39-cp39-win32.whl", hash = "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480"}, - {file = "protobuf-3.20.3-cp39-cp39-win_amd64.whl", hash = "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7"}, - {file = "protobuf-3.20.3-py2.py3-none-any.whl", hash = "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db"}, - {file = "protobuf-3.20.3.tar.gz", hash = "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2"}, -] -psutil = [ - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:8f024fbb26c8daf5d70287bb3edfafa22283c255287cf523c5d81721e8e5d82c"}, - {file = "psutil-5.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:b2f248ffc346f4f4f0d747ee1947963613216b06688be0be2e393986fe20dbbb"}, - {file = "psutil-5.9.2-cp27-cp27m-win32.whl", hash = "sha256:b1928b9bf478d31fdffdb57101d18f9b70ed4e9b0e41af751851813547b2a9ab"}, - {file = "psutil-5.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:404f4816c16a2fcc4eaa36d7eb49a66df2d083e829d3e39ee8759a411dbc9ecf"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:94e621c6a4ddb2573d4d30cba074f6d1aa0186645917df42c811c473dd22b339"}, - {file = "psutil-5.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:256098b4f6ffea6441eb54ab3eb64db9ecef18f6a80d7ba91549195d55420f84"}, - {file = "psutil-5.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:614337922702e9be37a39954d67fdb9e855981624d8011a9927b8f2d3c9625d9"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ec06dc6c934fb53df10c1672e299145ce609ff0611b569e75a88f313634969"}, - {file = "psutil-5.9.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3ac2c0375ef498e74b9b4ec56df3c88be43fe56cac465627572dbfb21c4be34"}, - {file = "psutil-5.9.2-cp310-cp310-win32.whl", hash = "sha256:e4c4a7636ffc47b7141864f1c5e7d649f42c54e49da2dd3cceb1c5f5d29bfc85"}, - {file = "psutil-5.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4cb67215c10d4657e320037109939b1c1d2fd70ca3d76301992f89fe2edb1f1"}, - {file = "psutil-5.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dc9bda7d5ced744622f157cc8d8bdd51735dafcecff807e928ff26bdb0ff097d"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75291912b945a7351d45df682f9644540d564d62115d4a20d45fa17dc2d48f8"}, - {file = "psutil-5.9.2-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4018d5f9b6651f9896c7a7c2c9f4652e4eea53f10751c4e7d08a9093ab587ec"}, - {file = "psutil-5.9.2-cp36-cp36m-win32.whl", hash = "sha256:f40ba362fefc11d6bea4403f070078d60053ed422255bd838cd86a40674364c9"}, - {file = "psutil-5.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9770c1d25aee91417eba7869139d629d6328a9422ce1cdd112bd56377ca98444"}, - {file = "psutil-5.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42638876b7f5ef43cef8dcf640d3401b27a51ee3fa137cb2aa2e72e188414c32"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91aa0dac0c64688667b4285fa29354acfb3e834e1fd98b535b9986c883c2ce1d"}, - {file = "psutil-5.9.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fb54941aac044a61db9d8eb56fc5bee207db3bc58645d657249030e15ba3727"}, - {file = "psutil-5.9.2-cp37-cp37m-win32.whl", hash = "sha256:7cbb795dcd8ed8fd238bc9e9f64ab188f3f4096d2e811b5a82da53d164b84c3f"}, - {file = "psutil-5.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5d39e3a2d5c40efa977c9a8dd4f679763c43c6c255b1340a56489955dbca767c"}, - {file = "psutil-5.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd331866628d18223a4265371fd255774affd86244fc307ef66eaf00de0633d5"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b315febaebae813326296872fdb4be92ad3ce10d1d742a6b0c49fb619481ed0b"}, - {file = "psutil-5.9.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7929a516125f62399d6e8e026129c8835f6c5a3aab88c3fff1a05ee8feb840d"}, - {file = "psutil-5.9.2-cp38-cp38-win32.whl", hash = "sha256:561dec454853846d1dd0247b44c2e66a0a0c490f937086930ec4b8f83bf44f06"}, - {file = "psutil-5.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:67b33f27fc0427483b61563a16c90d9f3b547eeb7af0ef1b9fe024cdc9b3a6ea"}, - {file = "psutil-5.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3591616fa07b15050b2f87e1cdefd06a554382e72866fcc0ab2be9d116486c8"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b29f581b5edab1f133563272a6011925401804d52d603c5c606936b49c8b97"}, - {file = "psutil-5.9.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4642fd93785a29353d6917a23e2ac6177308ef5e8be5cc17008d885cb9f70f12"}, - {file = "psutil-5.9.2-cp39-cp39-win32.whl", hash = "sha256:ed29ea0b9a372c5188cdb2ad39f937900a10fb5478dc077283bf86eeac678ef1"}, - {file = "psutil-5.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:68b35cbff92d1f7103d8f1db77c977e72f49fcefae3d3d2b91c76b0e7aef48b8"}, - {file = "psutil-5.9.2.tar.gz", hash = "sha256:feb861a10b6c3bb00701063b37e4afc754f8217f0f09c42280586bd6ac712b5c"}, -] -ptyprocess = [ - {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, - {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, -] -pure-eval = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pycodestyle = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, -] -pycparser = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] -pyflakes = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, -] -PyGithub = [ - {file = "PyGithub-1.55-py3-none-any.whl", hash = "sha256:2caf0054ea079b71e539741ae56c5a95e073b81fa472ce222e81667381b9601b"}, - {file = "PyGithub-1.55.tar.gz", hash = "sha256:1bbfff9372047ff3f21d5cd8e07720f3dbfdaf6462fcaed9d815f528f1ba7283"}, -] -Pygments = [ - {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, - {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, -] -pygtrie = [ - {file = "pygtrie-2.5.0-py3-none-any.whl", hash = "sha256:8795cda8105493d5ae159a5bef313ff13156c5d4d72feddefacaad59f8c8ce16"}, - {file = "pygtrie-2.5.0.tar.gz", hash = "sha256:203514ad826eb403dab1d2e2ddd034e0d1534bbe4dbe0213bb0593f66beba4e2"}, -] -pyhocon = [ - {file = "pyhocon-0.3.59.tar.gz", hash = "sha256:bb0eee59b57ecea5c30d14efc7ee7e55c935d58f03025ccdfc49237e920aa48c"}, -] -PyJWT = [ - {file = "PyJWT-2.5.0-py3-none-any.whl", hash = "sha256:8d82e7087868e94dd8d7d418e5088ce64f7daab4b36db654cbaedb46f9d1ca80"}, - {file = "PyJWT-2.5.0.tar.gz", hash = "sha256:e77ab89480905d86998442ac5788f35333fa85f65047a534adc38edf3c88fc3b"}, -] -pylint = [ - {file = "pylint-2.15.3-py3-none-any.whl", hash = "sha256:7f6aad1d8d50807f7bc64f89ac75256a9baf8e6ed491cc9bc65592bc3f462cf1"}, - {file = "pylint-2.15.3.tar.gz", hash = "sha256:5fdfd44af182866999e6123139d265334267339f29961f00c89783155eacc60b"}, -] -pyluach = [ - {file = "pyluach-2.0.1-py3-none-any.whl", hash = "sha256:0762d2cc23ee7cdc4be1e6ef59e137cc566dcf272084491004b478b7f5d0c0a3"}, - {file = "pyluach-2.0.1.tar.gz", hash = "sha256:9cafb36d16941fc843d3a88de4b3d6c4e477b5874adb8564c37baac7e4ed58df"}, -] -PyNaCl = [ - {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, - {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, - {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, - {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, - {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, -] -pyparsing = [ - {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, - {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, -] -pyrsistent = [ - {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"}, - {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"}, - {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"}, - {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"}, -] -PySide2 = [ - {file = "PySide2-5.15.2.1-5.15.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:b5e1d92f26b0bbaefff67727ccbb2e1b577f2c0164b349b3d6e80febb4c5bde2"}, - {file = "PySide2-5.15.2.1-5.15.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:235240b6ec8206d9fdf0232472c6ef3241783d480425e5b54796f06e39ed23da"}, - {file = "PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-abi3-macosx_10_13_intel.whl", hash = "sha256:a9e2e6bbcb5d2ebb421e46e72244a0f4fe0943b2288115f80a863aacc1de1f06"}, - {file = "PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-abi3-manylinux1_x86_64.whl", hash = "sha256:23886c6391ebd916e835fa1b5ae66938048504fd3a2934ae3189a96cd5ac0b46"}, - {file = "PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-none-win32.whl", hash = "sha256:439509e53cfe05abbf9a99422a2cbad086408b0f9bf5e6f642ff1b13b1f8b055"}, - {file = "PySide2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-none-win_amd64.whl", hash = "sha256:af6b263fe63ba6dea7eaebae80aa7b291491fe66f4f0057c0aafe780cc83da9d"}, -] -pytest = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, -] -pytest-cov = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, -] -pytest-forked = [ - {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, - {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, -] -pytest-xdist = [ - {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, - {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -pytz = [ - {file = "pytz-2022.4-py2.py3-none-any.whl", hash = "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91"}, - {file = "pytz-2022.4.tar.gz", hash = "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174"}, -] -pytz-deprecation-shim = [ - {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"}, - {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"}, -] -pyupgrade = [ - {file = "pyupgrade-3.0.0-py2.py3-none-any.whl", hash = "sha256:f9ba6cb58713e7249f4f0486e425969618e953062a5fc805da9d21602a2d1441"}, - {file = "pyupgrade-3.0.0.tar.gz", hash = "sha256:6ec1e2762d887cab94a5714b2ea7e944843d8c2de36c449d443e52ffac8ab14f"}, -] -pywin32 = [ - {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, - {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, - {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, - {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, - {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, - {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, - {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, - {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, - {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, - {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, - {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, - {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, - {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, - {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, -] -pywinauto = [ - {file = "pywinauto-0.6.8-py2.py3-none-any.whl", hash = "sha256:931ce622d7f402b1892ab472987a1332e4c0681bf87e106f798390d16ca95e58"}, - {file = "pywinauto-0.6.8.tar.gz", hash = "sha256:de23f1e977cc51e7eddd95c8f365710343136433968d1e2ad377962d6bd6540a"}, -] -PyYAML = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -pyzmq = [ - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"}, - {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"}, - {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"}, - {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"}, - {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"}, - {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"}, - {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"}, - {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"}, - {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"}, - {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"}, - {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"}, - {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"}, - {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"}, - {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"}, - {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"}, - {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"}, - {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"}, - {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"}, - {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"}, - {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"}, - {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"}, - {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"}, - {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"}, - {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"}, - {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"}, - {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"}, - {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"}, - {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"}, - {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"}, - {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"}, - {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"}, - {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"}, -] -QtPy = [ - {file = "QtPy-2.2.1-py3-none-any.whl", hash = "sha256:268cf5328f41353be1b127e04a81bc74ec9a9b54c9ac75dd8fe0ff48d8ad6ead"}, - {file = "QtPy-2.2.1.tar.gz", hash = "sha256:7d5231133b772e40b4ee514b6673aca558331e4b88ca038b26c9e16c5c95524f"}, -] -requests = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, -] -Rx = [ - {file = "Rx-3.2.0-py3-none-any.whl", hash = "sha256:922c5f4edb3aa1beaa47bf61d65d5380011ff6adcd527f26377d05cb73ed8ec8"}, - {file = "Rx-3.2.0.tar.gz", hash = "sha256:b657ca2b45aa485da2f7dcfd09fac2e554f7ac51ff3c2f8f2ff962ecd963d91c"}, -] -schedule = [ - {file = "schedule-1.1.0-py2.py3-none-any.whl", hash = "sha256:617adce8b4bf38c360b781297d59918fbebfb2878f1671d189f4f4af5d0567a4"}, - {file = "schedule-1.1.0.tar.gz", hash = "sha256:e6ca13585e62c810e13a08682e0a6a8ad245372e376ba2b8679294f377dfc8e4"}, -] -Send2Trash = [ - {file = "Send2Trash-1.8.0-py3-none-any.whl", hash = "sha256:f20eaadfdb517eaca5ce077640cb261c7d2698385a6a0f072a4a5447fd49fa08"}, - {file = "Send2Trash-1.8.0.tar.gz", hash = "sha256:d2c24762fd3759860a0aff155e45871447ea58d2be6bdd39b5c8f966a0c99c2d"}, -] -setuptools = [ - {file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"}, - {file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"}, -] -shiboken2 = [ - {file = "shiboken2-5.15.2.1-5.15.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:f890f5611ab8f48b88cfecb716da2ac55aef99e2923198cefcf781842888ea65"}, - {file = "shiboken2-5.15.2.1-5.15.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87079c07587859a525b9800d60b1be971338ce9b371d6ead81f15ee5a46d448b"}, - {file = "shiboken2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-abi3-macosx_10_13_intel.whl", hash = "sha256:ffd3d0ec3d508e592d7ee3885d27fee1f279a49989f734eb130f46d9501273a9"}, - {file = "shiboken2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-abi3-manylinux1_x86_64.whl", hash = "sha256:63debfcc531b6a2b4985aa9b71433d2ad3bac542acffc729cc0ecaa3854390c0"}, - {file = "shiboken2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-none-win32.whl", hash = "sha256:eb0da44b6fa60c6bd317b8f219e500595e94e0322b33ec5b4e9f406bedaee555"}, - {file = "shiboken2-5.15.2.1-5.15.2-cp35.cp36.cp37.cp38.cp39.cp310-none-win_amd64.whl", hash = "sha256:a0d0fdeb12b72c8af349b9642ccc67afd783dca449309f45e78cda50272fd6b7"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -snowballstemmer = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] -soupsieve = [ - {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, - {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, -] -Sphinx = [ - {file = "Sphinx-5.2.3.tar.gz", hash = "sha256:5b10cb1022dac8c035f75767799c39217a05fc0fe2d6fe5597560d38e44f0363"}, - {file = "sphinx-5.2.3-py3-none-any.whl", hash = "sha256:7abf6fabd7b58d0727b7317d5e2650ef68765bbe0ccb63c8795fa8683477eaa2"}, -] -sphinx-autoapi = [ - {file = "sphinx-autoapi-2.0.0.tar.gz", hash = "sha256:97dcf1b5b54cd0d8efef867594e4a4f3e2d3a2c0ec1e5a891e0a61bc77046006"}, - {file = "sphinx_autoapi-2.0.0-py2.py3-none-any.whl", hash = "sha256:dab2753a38cad907bf4e61473c0da365a26bfbe69fbf5aa6e4f7d48e1cf8a148"}, -] -sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, - {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, -] -sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, -] -sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, - {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, -] -sphinxcontrib-jsmath = [ - {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, - {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, -] -sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, -] -sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, -] -SQLAlchemy = [ - {file = "SQLAlchemy-1.4.41-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:13e397a9371ecd25573a7b90bd037db604331cf403f5318038c46ee44908c44d"}, - {file = "SQLAlchemy-1.4.41-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2d6495f84c4fd11584f34e62f9feec81bf373787b3942270487074e35cbe5330"}, - {file = "SQLAlchemy-1.4.41-cp27-cp27m-win32.whl", hash = "sha256:e570cfc40a29d6ad46c9aeaddbdcee687880940a3a327f2c668dd0e4ef0a441d"}, - {file = "SQLAlchemy-1.4.41-cp27-cp27m-win_amd64.whl", hash = "sha256:5facb7fd6fa8a7353bbe88b95695e555338fb038ad19ceb29c82d94f62775a05"}, - {file = "SQLAlchemy-1.4.41-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f37fa70d95658763254941ddd30ecb23fc4ec0c5a788a7c21034fc2305dab7cc"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:361f6b5e3f659e3c56ea3518cf85fbdae1b9e788ade0219a67eeaaea8a4e4d2a"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0990932f7cca97fece8017414f57fdd80db506a045869d7ddf2dda1d7cf69ecc"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cd767cf5d7252b1c88fcfb58426a32d7bd14a7e4942497e15b68ff5d822b41ad"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5102fb9ee2c258a2218281adcb3e1918b793c51d6c2b4666ce38c35101bb940e"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-win32.whl", hash = "sha256:2082a2d2fca363a3ce21cfa3d068c5a1ce4bf720cf6497fb3a9fc643a8ee4ddd"}, - {file = "SQLAlchemy-1.4.41-cp310-cp310-win_amd64.whl", hash = "sha256:e4b12e3d88a8fffd0b4ca559f6d4957ed91bd4c0613a4e13846ab8729dc5c251"}, - {file = "SQLAlchemy-1.4.41-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:90484a2b00baedad361402c257895b13faa3f01780f18f4a104a2f5c413e4536"}, - {file = "SQLAlchemy-1.4.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b67fc780cfe2b306180e56daaa411dd3186bf979d50a6a7c2a5b5036575cbdbb"}, - {file = "SQLAlchemy-1.4.41-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ad2b727fc41c7f8757098903f85fafb4bf587ca6605f82d9bf5604bd9c7cded"}, - {file = "SQLAlchemy-1.4.41-cp311-cp311-win32.whl", hash = "sha256:59bdc291165b6119fc6cdbc287c36f7f2859e6051dd923bdf47b4c55fd2f8bd0"}, - {file = "SQLAlchemy-1.4.41-cp311-cp311-win_amd64.whl", hash = "sha256:d2e054aed4645f9b755db85bc69fc4ed2c9020c19c8027976f66576b906a74f1"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:4ba7e122510bbc07258dc42be6ed45997efdf38129bde3e3f12649be70683546"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0dcf127bb99458a9d211e6e1f0f3edb96c874dd12f2503d4d8e4f1fd103790b"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e16c2be5cb19e2c08da7bd3a87fed2a0d4e90065ee553a940c4fc1a0fb1ab72b"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebeeec5c14533221eb30bad716bc1fd32f509196318fb9caa7002c4a364e4c"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-win32.whl", hash = "sha256:3e2ef592ac3693c65210f8b53d0edcf9f4405925adcfc031ff495e8d18169682"}, - {file = "SQLAlchemy-1.4.41-cp36-cp36m-win_amd64.whl", hash = "sha256:eb30cf008850c0a26b72bd1b9be6730830165ce049d239cfdccd906f2685f892"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:c23d64a0b28fc78c96289ffbd0d9d1abd48d267269b27f2d34e430ea73ce4b26"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb8897367a21b578b26f5713833836f886817ee2ffba1177d446fa3f77e67c8"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:14576238a5f89bcf504c5f0a388d0ca78df61fb42cb2af0efe239dc965d4f5c9"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:639e1ae8d48b3c86ffe59c0daa9a02e2bfe17ca3d2b41611b30a0073937d4497"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-win32.whl", hash = "sha256:0005bd73026cd239fc1e8ccdf54db58b6193be9a02b3f0c5983808f84862c767"}, - {file = "SQLAlchemy-1.4.41-cp37-cp37m-win_amd64.whl", hash = "sha256:5323252be2bd261e0aa3f33cb3a64c45d76829989fa3ce90652838397d84197d"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:05f0de3a1dc3810a776275763764bb0015a02ae0f698a794646ebc5fb06fad33"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0002e829142b2af00b4eaa26c51728f3ea68235f232a2e72a9508a3116bd6ed0"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22ff16cedab5b16a0db79f1bc99e46a6ddececb60c396562e50aab58ddb2871c"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccfd238f766a5bb5ee5545a62dd03f316ac67966a6a658efb63eeff8158a4bbf"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-win32.whl", hash = "sha256:58bb65b3274b0c8a02cea9f91d6f44d0da79abc993b33bdedbfec98c8440175a"}, - {file = "SQLAlchemy-1.4.41-cp38-cp38-win_amd64.whl", hash = "sha256:ce8feaa52c1640de9541eeaaa8b5fb632d9d66249c947bb0d89dd01f87c7c288"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:199a73c31ac8ea59937cc0bf3dfc04392e81afe2ec8a74f26f489d268867846c"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676d51c9f6f6226ae8f26dc83ec291c088fe7633269757d333978df78d931ab"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:036d8472356e1d5f096c5e0e1a7e0f9182140ada3602f8fff6b7329e9e7cfbcd"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2307495d9e0ea00d0c726be97a5b96615035854972cc538f6e7eaed23a35886c"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-win32.whl", hash = "sha256:9c56e19780cd1344fcd362fd6265a15f48aa8d365996a37fab1495cae8fcd97d"}, - {file = "SQLAlchemy-1.4.41-cp39-cp39-win_amd64.whl", hash = "sha256:f5fa526d027d804b1f85cdda1eb091f70bde6fb7d87892f6dd5a48925bc88898"}, - {file = "SQLAlchemy-1.4.41.tar.gz", hash = "sha256:0292f70d1797e3c54e862e6f30ae474014648bc9c723e14a2fda730adb0a9791"}, -] -stack-data = [ - {file = "stack_data-0.5.1-py3-none-any.whl", hash = "sha256:5120731a18ba4c82cefcf84a945f6f3e62319ef413bfc210e32aca3a69310ba2"}, - {file = "stack_data-0.5.1.tar.gz", hash = "sha256:95eb784942e861a3d80efd549ff9af6cf847d88343a12eb681d7157cfcb6e32b"}, -] -tabulate = [ - {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, - {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, -] -tinycss2 = [ - {file = "tinycss2-1.1.1-py3-none-any.whl", hash = "sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8"}, - {file = "tinycss2-1.1.1.tar.gz", hash = "sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf"}, -] -tokenize-rt = [ - {file = "tokenize_rt-5.0.0-py2.py3-none-any.whl", hash = "sha256:c67772c662c6b3dc65edf66808577968fb10badfc2042e3027196bed4daf9e5a"}, - {file = "tokenize_rt-5.0.0.tar.gz", hash = "sha256:3160bc0c3e8491312d0485171dea861fc160a240f5f5766b72a1165408d10740"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -tomlkit = [ - {file = "tomlkit-0.11.5-py3-none-any.whl", hash = "sha256:f2ef9da9cef846ee027947dc99a45d6b68a63b0ebc21944649505bf2e8bc5fe7"}, - {file = "tomlkit-0.11.5.tar.gz", hash = "sha256:571854ebbb5eac89abcb4a2e47d7ea27b89bf29e09c35395da6f03dd4ae23d1c"}, -] -toolz = [ - {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, - {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, -] -tornado = [ - {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"}, - {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"}, - {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"}, - {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"}, - {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"}, - {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"}, - {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, -] -tqdm = [ - {file = "tqdm-4.64.1-py2.py3-none-any.whl", hash = "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"}, - {file = "tqdm-4.64.1.tar.gz", hash = "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4"}, -] -traitlets = [ - {file = "traitlets-5.4.0-py3-none-any.whl", hash = "sha256:93663cc8236093d48150e2af5e2ed30fc7904a11a6195e21bab0408af4e6d6c8"}, - {file = "traitlets-5.4.0.tar.gz", hash = "sha256:3f2c4e435e271592fe4390f1746ea56836e3a080f84e7833f0f801d9613fec39"}, -] -typing-extensions = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] -tzdata = [ - {file = "tzdata-2022.4-py2.py3-none-any.whl", hash = "sha256:74da81ecf2b3887c94e53fc1d466d4362aaf8b26fc87cda18f22004544694583"}, - {file = "tzdata-2022.4.tar.gz", hash = "sha256:ada9133fbd561e6ec3d1674d3fba50251636e918aa97bd59d63735bef5a513bb"}, -] -tzlocal = [ - {file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"}, - {file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"}, -] -Unidecode = [ - {file = "Unidecode-1.3.6-py3-none-any.whl", hash = "sha256:547d7c479e4f377b430dd91ac1275d593308dce0fc464fb2ab7d41f82ec653be"}, - {file = "Unidecode-1.3.6.tar.gz", hash = "sha256:fed09cf0be8cf415b391642c2a5addfc72194407caee4f98719e40ec2a72b830"}, -] -urllib3 = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, -] -virtualenv = [ - {file = "virtualenv-20.16.5-py3-none-any.whl", hash = "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"}, - {file = "virtualenv-20.16.5.tar.gz", hash = "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da"}, -] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] -webencodings = [ - {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, - {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, -] -wheel = [ - {file = "wheel-0.37.1-py2.py3-none-any.whl", hash = "sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a"}, - {file = "wheel-0.37.1.tar.gz", hash = "sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4"}, -] -windows-curses = [ - {file = "windows_curses-2.3.0-cp310-cp310-win32.whl", hash = "sha256:a3a63a0597729e10f923724c2cf972a23ea677b400d2387dee1d668cf7116177"}, - {file = "windows_curses-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:7a35eda4cb120b9e1a5ae795f3bc06c55b92c9d391baba6be1903285a05f3551"}, - {file = "windows_curses-2.3.0-cp36-cp36m-win32.whl", hash = "sha256:4d5fb991d1b90a41c2332f02241a1f84c8a1e6bc8f6e0d26f532d0da7a9f7b51"}, - {file = "windows_curses-2.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:170c0d941c2e0cdf864e7f0441c1bdf0709232bf4aa7ce7f54d90fc76a4c0504"}, - {file = "windows_curses-2.3.0-cp37-cp37m-win32.whl", hash = "sha256:d5cde8ec6d582aa77af791eca54f60858339fb3f391945f9cad11b1ab71062e3"}, - {file = "windows_curses-2.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e913dc121446d92b33fe4f5bcca26d3a34e4ad19f2af160370d57c3d1e93b4e1"}, - {file = "windows_curses-2.3.0-cp38-cp38-win32.whl", hash = "sha256:fbc2131cec57e422c6660e6cdb3420aff5be5169b8e45bb7c471f884b0590a2b"}, - {file = "windows_curses-2.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cc5fa913780d60f4a40824d374a4f8ca45b4e205546e83a2d85147315a57457e"}, - {file = "windows_curses-2.3.0-cp39-cp39-win32.whl", hash = "sha256:935be95cfdb9213f6f5d3d5bcd489960e3a8fbc9b574e7b2e8a3a3cc46efff49"}, - {file = "windows_curses-2.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:c860f596d28377e47f322b7382be4d3573fd76d1292234996bb7f72e0bc0ed0d"}, -] -wrapt = [ - {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, - {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, - {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, - {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, - {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, - {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, - {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, - {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, - {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, - {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, - {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, - {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, - {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, - {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, - {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, - {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, -] -yarl = [ - {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"}, - {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"}, - {file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"}, - {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"}, - {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"}, - {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"}, - {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"}, - {file = "yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"}, - {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"}, - {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"}, - {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"}, - {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"}, - {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"}, - {file = "yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"}, - {file = "yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"}, - {file = "yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"}, - {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"}, - {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"}, - {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"}, - {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"}, - {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"}, - {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"}, - {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"}, - {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"}, - {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"}, - {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"}, - {file = "yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"}, - {file = "yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"}, - {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"}, - {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"}, - {file = "yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"}, - {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"}, - {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"}, - {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"}, - {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"}, - {file = "yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"}, - {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"}, - {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"}, - {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"}, - {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"}, - {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"}, - {file = "yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"}, - {file = "yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"}, - {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"}, - {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"}, - {file = "yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"}, - {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"}, - {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"}, - {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"}, - {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"}, - {file = "yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"}, - {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"}, - {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"}, - {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"}, - {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"}, - {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"}, - {file = "yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"}, - {file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"}, - {file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"}, -] -zipp = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, -] diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 00000000..b25bdf39 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,1265 @@ + + + + + + + + Python Module Index — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ + +

Python Module Index

+ +
+ k +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ k
+ koapy +
    + koapy.backend +
    + koapy.backend.daishin_cybos_plus +
    + koapy.backend.daishin_cybos_plus.core +
    + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint +
    + koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin +
    + koapy.backend.daishin_cybos_plus.core.CybosPlusError +
    + koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter +
    + koapy.backend.daishin_cybos_plus.proxy +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2 +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils +
    + koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer +
    + koapy.backend.kiwoom_open_api_plus +
    + koapy.backend.kiwoom_open_api_plus.core +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec +
    + koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater +
    + koapy.backend.kiwoom_open_api_plus.core.tools +
    + koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs +
    + koapy.backend.kiwoom_open_api_plus.grpc +
    + koapy.backend.kiwoom_open_api_plus.grpc.event +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2 +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer +
    + koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer +
    + koapy.backend.kiwoom_open_api_plus.grpc.tools +
    + koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto +
    + koapy.backend.kiwoom_open_api_plus.pyside2 +
    + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler +
    + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication +
    + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication +
    + koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler +
    + koapy.backend.kiwoom_open_api_plus.utils +
    + koapy.backend.kiwoom_open_api_plus.utils.grpc +
    + koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous +
    + koapy.backend.kiwoom_open_api_plus.utils.list_conversion +
    + koapy.backend.kiwoom_open_api_plus.utils.module_path +
    + koapy.backend.kiwoom_open_api_plus.utils.pyside2 +
    + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler +
    + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler +
    + koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor +
    + koapy.backend.kiwoom_open_api_plus.utils.queue +
    + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator +
    + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver +
    + koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator +
    + koapy.backend.kiwoom_open_api_w +
    + koapy.backend.kiwoom_open_api_w.core +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEntrypoint +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector +
    + koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature +
    + koapy.backtrader +
    + koapy.backtrader.KiwoomOpenApiPlusBroker +
    + koapy.backtrader.KiwoomOpenApiPlusData +
    + koapy.backtrader.KiwoomOpenApiPlusEventStreamer +
    + koapy.backtrader.KiwoomOpenApiPlusStore +
    + koapy.backtrader.KrxHistoricalDailyPriceData +
    + koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite +
    + koapy.backtrader.KrxTradingCalendar +
    + koapy.backtrader.SQLAlchemyData +
    + koapy.backtrader.SQLAlchemySQLiteData +
    + koapy.backtrader.SQLiteData +
    + koapy.cli +
    + koapy.cli.__main__ +
    + koapy.cli.commands +
    + koapy.cli.commands.disable +
    + koapy.cli.commands.disable.auto_login +
    + koapy.cli.commands.enable +
    + koapy.cli.commands.enable.auto_login +
    + koapy.cli.commands.generate +
    + koapy.cli.commands.generate.grpc +
    + koapy.cli.commands.generate.grpc.ssl_credentials +
    + koapy.cli.commands.generate.openapi +
    + koapy.cli.commands.generate.openapi.python_stubs +
    + koapy.cli.commands.get +
    + koapy.cli.commands.get.account_data +
    + koapy.cli.commands.get.account_data.deposit +
    + koapy.cli.commands.get.account_data.evaluation +
    + koapy.cli.commands.get.account_data.orders +
    + koapy.cli.commands.get.account_data.userinfo +
    + koapy.cli.commands.get.chart_data +
    + koapy.cli.commands.get.chart_data.daily +
    + koapy.cli.commands.get.chart_data.minute +
    + koapy.cli.commands.get.openapi_meta +
    + koapy.cli.commands.get.openapi_meta.errmsg +
    + koapy.cli.commands.get.openapi_meta.modulepath +
    + koapy.cli.commands.get.openapi_meta.realinfo +
    + koapy.cli.commands.get.openapi_meta.trinfo +
    + koapy.cli.commands.get.stock_meta +
    + koapy.cli.commands.get.stock_meta.codelist +
    + koapy.cli.commands.get.stock_meta.codelist_interactive +
    + koapy.cli.commands.get.stock_meta.stockcode +
    + koapy.cli.commands.get.stock_meta.stockinfo +
    + koapy.cli.commands.get.stock_meta.stockname +
    + koapy.cli.commands.install +
    + koapy.cli.commands.install.openapi +
    + koapy.cli.commands.install.pywin32 +
    + koapy.cli.commands.serve +
    + koapy.cli.commands.show +
    + koapy.cli.commands.show.account_window +
    + koapy.cli.commands.uninstall +
    + koapy.cli.commands.uninstall.openapi +
    + koapy.cli.commands.uninstall.pywin32 +
    + koapy.cli.commands.update +
    + koapy.cli.extensions +
    + koapy.cli.extensions.functools +
    + koapy.cli.extensions.parser +
    + koapy.cli.extensions.verbose_option +
    + koapy.cli.utils +
    + koapy.cli.utils.credentials +
    + koapy.cli.utils.fail_with_usage +
    + koapy.cli.utils.grpc_options +
    + koapy.cli.utils.openapi +
    + koapy.cli.utils.pywin32 +
    + koapy.cli.utils.verbose_option +
    + koapy.compat +
    + koapy.compat.pyside2 +
    + koapy.compat.pyside2.QtAxContainer +
    + koapy.compat.pyside2.QtCore +
    + koapy.compat.pyside2.QtGui +
    + koapy.compat.pyside2.QtNetwork +
    + koapy.compat.pyside2.QtWidgets +
    + koapy.compat.pywinauto +
    + koapy.compat.pywinauto.findwindows +
    + koapy.compat.pywinauto.importlib +
    + koapy.compat.pywinauto.timings +
    + koapy.config +
    + koapy.utils +
    + koapy.utils.builtin +
    + koapy.utils.ctypes +
    + koapy.utils.data +
    + koapy.utils.data.KrxHistoricalDailyPriceDataDownloader +
    + koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader +
    + koapy.utils.data.KrxHistoricalDailyPriceDataLoader +
    + koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader +
    + koapy.utils.datetime +
    + koapy.utils.exchange_calendars +
    + koapy.utils.grpc +
    + koapy.utils.itertools +
    + koapy.utils.logging +
    + koapy.utils.logging.Logging +
    + koapy.utils.logging.pyside2 +
    + koapy.utils.logging.pyside2.QAbstractSocketLogging +
    + koapy.utils.logging.pyside2.QObjectLogging +
    + koapy.utils.logging.pyside2.QThreadLogging +
    + koapy.utils.logging.pyside2.QWidgetLogging +
    + koapy.utils.logging.tqdm +
    + koapy.utils.logging.tqdm.TqdmStreamHandler +
    + koapy.utils.messaging +
    + koapy.utils.messaging.DiscordMessenger +
    + koapy.utils.messaging.Messenger +
    + koapy.utils.networking +
    + koapy.utils.notimplemented +
    + koapy.utils.platform +
    + koapy.utils.pywin32 +
    + koapy.utils.rate_limiting +
    + koapy.utils.rate_limiting.pyside2 +
    + koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor +
    + koapy.utils.rate_limiting.RateLimiter +
    + koapy.utils.recursion +
    + koapy.utils.serialization +
    + koapy.utils.store +
    + koapy.utils.store.misc +
    + koapy.utils.store.misc.VersionedItem +
    + koapy.utils.store.sqlalchemy +
    + koapy.utils.store.sqlalchemy.Base +
    + koapy.utils.store.sqlalchemy.Library +
    + koapy.utils.store.sqlalchemy.Session +
    + koapy.utils.store.sqlalchemy.Snapshot +
    + koapy.utils.store.sqlalchemy.SnapshotAssociation +
    + koapy.utils.store.sqlalchemy.Symbol +
    + koapy.utils.store.sqlalchemy.Timestamp +
    + koapy.utils.store.sqlalchemy.Version +
    + koapy.utils.store.SQLiteFileLibrary +
    + koapy.utils.store.SQLiteStore +
    + koapy.utils.store.SQLiteStoreLibrary +
    + koapy.utils.subprocess +
    + koapy.utils.threading +
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 57a8c77f..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,116 +0,0 @@ -[tool.poetry] -name = "koapy" -version = "0.9.0" -description = "Kiwoom Open Api Plus Python" -license = "MIT OR Apache-2.0 OR GPL-3.0-or-later" -authors = ["Yunseong Hwang "] -maintainers = ["Yunseong Hwang "] -readme = "README.rst" -homepage = "https://github.com/elbakramer/koapy" -repository = "https://github.com/elbakramer/koapy" -documentation = "https://koapy.readthedocs.io/en/latest/" -keywords = ["kiwoom", "kiwoom-open-api"] -classifiers = [ - "Development Status :: 2 - Pre-Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "License :: OSI Approved :: Apache Software License", - "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", - "Natural Language :: English", - "Natural Language :: Korean", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Operating System :: Microsoft :: Windows :: Windows 10", - "Environment :: Console", - "Environment :: X11 Applications :: Qt", - "Topic :: Office/Business :: Financial", -] -include = [ - "docs", - "tests", - "*.rst", - "LICENSE", - "LICENSE.*", -] - -[tool.poetry.urls] -"Bug Tracker" = "https://github.com/elbakramer/koapy/issues" - -[tool.poetry.dependencies] -# main runtime dependencies -python = ">=3.8.1,<3.11" -click = "^8.1.3" -cryptography = "^38.0.1" -deprecated = "^1.2.13" -"discord.py" = "^2.0.1" -exchange-calendars = "^4.2.3" -grpcio = "==1.48.2" # app crashes on 1.49.1 (possibly related: https://github.com/grpc/grpc/issues/31240) -grpcio-tools = "==1.48.2" -lxml = "^4.9.1" -numpy = "^1.23.3" -openpyxl = "^3.0.10" -pandas = "^1.5.0" -psutil = "^5.9.0" -pygtrie = "^2.5.0" -pyhocon = "^0.3.59" -PySide2 = "^5.15.2.1" -pytz = "^2022.4" -QtPy = "^2.2.1" -requests = "^2.28.1" -Rx = "^3.2.0" -schedule = "^1.1.0" -Send2Trash = "^1.8.0" -SQLAlchemy = "^1.4.41" -tabulate = "^0.9.0" -tqdm = "^4.64.1" -tzlocal = "^4.2" -wrapt = "^1.14.1" - -# windows specific dependencies -pywin32 = { version = "^304", markers = "sys_platform == 'win32'" } -pywinauto = { version = "^0.6.8", markers = "sys_platform == 'win32'" } -windows-curses = { version = "^2.3.0", markers = "sys_platform == 'win32'" } - -# python compatibility backports for runtime -typing-extensions = { version = "^4.4.0", markers = "python_version < '3.10'" } - -[tool.poetry.dev-dependencies] -# development dependencies -actions-toolkit = "^0.1.13" -black = "^22.10.0" -bump2version = "^1.0.1" -codecov = "^2.1.12" -coverage = "^6.5.0" -dunamai = "^1.13.1" -flake8 = "^5.0.4" -isort = "^5.10.1" -mypy = "^0.982" -pip-tools = "^6.6.0" -pre-commit = "^2.20.0" -pylint = "^2.15.3" -pytest = "^7.1.3" -pytest-cov = "^4.0.0" -pytest-xdist = "^2.5.0" -pyupgrade = "^3.0.0" - -# python compatibility backports for development -astunparse = { version = "^1.6.3", markers = "python_version < '3.9'" } - -# documentation dependencies -Sphinx = "^5.2.3" -sphinx-autoapi = "^2.0.0" -nbconvert = "^7.2.1" -nbsphinx = "^0.8.9" -ipython = "^8.5.0" - -[tool.poetry.scripts] -koapy = "koapy.cli:main" - -[tool.black] -line-length = 88 -force-exclude = "((.+)_pb2.py|(.+)_pb2_grpc.py)" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index b673ca07..00000000 --- a/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -testpaths = koapy tests docs diff --git a/readme.html b/readme.html new file mode 100644 index 00000000..09b41304 --- /dev/null +++ b/readme.html @@ -0,0 +1,1064 @@ + + + + + + + + + KOAPY — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

KOAPY

+
+PyPI Version +PyPI Python Versions +PyPI Status +
+
+CI Build Status +Documentation Build Status +Codecov Coverage +Requires.io Requirements Status +
+
+PyPI License +
+
+Gitter Chat +Code Style: Black +
+

Kiwoom Open Api Plus Python

+ +
+

Introduction

+

KOAPY 는 키움증권의 OpenAPI+ 를 Python 에서 쉽게 사용할 수 있도록 만든 +라이브러리 패키지 및 툴입니다.

+

키움에서 제공하는 OpenAPI+ 를 활용하는데 필요한 구체적인 지식들을 전혀 알지 못해도, +기본적인 Python 에 대한 지식만 어느 정도 있다면 쉽게 사용할 수 있도록 하는 것에 +초점을 두었습니다.

+

예를 들어 Python 기준으로 아래와 같은 내용들을 잘 모르더라도 충분히 모든 기능을 +사용할 수 있음을 의미합니다.

+
    +
  • 키움에서 제공하는 OpenAPI+ 의 OCX 라이브러리 구조

  • +
  • OCX 를 Python 에서 구동하기 위해 PyQt5/PySide2 라이브러리의 QAxWidget 생성

  • +
  • 컨트롤에서 함수 호출을 위해 dynamicCall 함수 사용

  • +
  • 이벤트 처리를 위해 적절한 signal/slot 설정 및 이벤트 처리

  • +
+
+
+

Showcase

+
+

테이블 데이터 처리를 위한 pandas 임포트

+
>>> import pandas as pd
+
+
+
+
+

엔트리포인트 객체 생성

+
>>> from koapy import KiwoomOpenApiPlusEntrypoint
+
+
+
>>> entrypoint = KiwoomOpenApiPlusEntrypoint()
+
+
+
+
+

키움증권 서버와의 연결 확인 및 로그인 처리

+
>>> entrypoint.IsConnected()
+False
+>>> entrypoint.EnsureConnected()
+True
+>>> entrypoint.IsConnected()
+True
+
+
+
+
+

종목 리스트 및 종목 코드와 이름 확인

+
>>> code_list = entrypoint.GetCodeListByMarketAsList("0")
+>>> code_list
+['000020', '000040', '000050', '000060', '000070', ...]
+
+
+
>>> name_list = [entrypoint.GetMasterCodeName(code) for code in code_list]
+>>> name_list
+['동화약품', 'KR모터스', '경방', '메리츠화재', '삼양홀딩스', ...]
+
+
+
>>> code_by_name = {name: code for code, name in zip(code_list, name_list)}
+
+
+
>>> name = "삼성전자"
+>>> code = code_by_name[name]
+>>> code
+'005930'
+
+
+
+
+

단일 종목의 기본정보 확인

+
>>> info = entrypoint.GetStockBasicInfoAsDict(code)
+>>> info
+{'종목코드': '005930', '종목명': '삼성전자', '결산월': '12', '액면가': '100', '자본금': '7780', '상장주식': '5969783', '신용비율': '+0.12', '연중최고': '+79800', '연중최저': '-71200', '시가총액': '4417639', '시가총액비중': '', '외인소진률': '+52.09', '대용가': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '매출액': '2368070', '영업이익': '359939', '당기순이익': '264078', '250최고': '+86400', '250최저': '-68300', '시가': '+74300', '고가': '+74600', '저가': '+73400', '상한가': '+95200', '하한가': '-51400', '기준가': '73300', '예상체결가': '-0', '예상체결수량': '0', '250최고가일': '20210202', '250최고가대비율': '-14.35', '250최저가일': '20211013', '250최저가대비율': '+8.35', '현재가': '+74000', '대비기호': '2', '전일대비': '+700', '등락율': '+0.95', '거래량': '12730034', '거래대비': '-71.74', '액면가단위': '원', '유통주식': '4459119', '유통비율': '74.7'}
+
+
+
+
+

복수 종목의 기본정보 확인

+
>>> code_list_info = entrypoint.GetStockQuoteInfoAsDataFrame(code_list)
+>>> code_list_info
+        종목코드                      종목명     현재가    기준가   전일대비 전일대비기호    등락율  \
+0     000020                     동화약품  +12450  12300   +150      2  +1.22
+1     000040                    KR모터스    +810    790    +20      2  +2.53
+2     000050                       경방  +14450  14200   +250      2  +1.76
+3     000060                    메리츠화재   49450  49450      0      3   0.00
+4     000070                    삼양홀딩스  +90700  88400  +2300      2  +2.60
+...      ...                      ...     ...    ...    ...    ...    ...
+1744  580031  KB 인버스 KOSDAQ150 선물 ETN  -10930  10960    -30      5  -0.27
+1745  580032     KB 레버리지 구리 선물 ETN(H)  -20515  20560    -45      5  -0.22
+1746  580033   KB 인버스 2X 구리 선물 ETN(H)  +18350  18280    +70      2  +0.38
+1747  580010         KB Wise 분할매매 ETN  +10820  10770    +50      2  +0.46
+1748  590018       미래에셋 중국 심천 100 ETN  +18810  18645   +165      2  +0.88
+
+        거래량   거래대금   체결량  ...    ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가  \
+0     135513   1670  +500  ...  00000000
+1     230165    186   -10  ...  00000000
+2       6214     89    97  ...  00000000
+3     411584  20423    -4  ...  00000000
+4       9052    813    +5  ...  00000000
+...      ...    ...   ...  ...       ...   ...     ...  ..   ... .. .. .. ..
+1744       2      0    -1  ...  00000000
+1745       0      0        ...  00000000
+1746      17      0   +10  ...  00000000
+1747       0      0        ...  00000000
+1748       1      0    +1  ...  00000000
+
+    로
+0
+1
+2
+3
+4
+...  ..
+1744
+1745
+1746
+1747
+1748
+
+[1749 rows x 63 columns]
+
+
+
+
+

특정 종목의 차트 데이터 확인

+
>>> chart_data = entrypoint.GetDailyStockDataAsDataFrame(code)
+>>> chart_data
+        종목코드    현재가       거래량     거래대금        일자     시가     고가     저가 수정주가구분  \
+0     005930  74000  12730034   941413  20220204  74300  74600  73400
+1             73300  17744721  1314506  20220203  74900  74900  73300
+2             73300  21367447  1552586  20220128  71300  73700  71200
+3             71300  22274777  1603685  20220127  73800  74000  71300
+4             73300  12976730   955547  20220126  73900  74400  73100
+...      ...    ...       ...      ...       ...    ...    ...    ...    ...
+9797           8010      4970        1  19850109   8240   8240   7950
+9798           8300     12930        4  19850108   8400   8400   8300
+9799           8410     11810        3  19850107   8400   8500   8390
+9800           8390      1660        0  19850105   8400   8440   8390
+9801           8450      1710        0  19850104   8500   8500   8450
+
+    수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가
+0
+1
+2
+3
+4
+...   ...   ...   ...  ...     ...  ...
+9797
+9798
+9799
+9800
+9801
+
+[9802 rows x 15 columns]
+
+
+
+
+

키움증권의 TR 메타 정보 확인

+
>>> from koapy import KiwoomOpenApiPlusTrInfo
+
+
+
>>> tr_info_list = KiwoomOpenApiPlusTrInfo.get_trinfo_list()
+
+
+
>>> data = pd.DataFrame.from_records([(info.tr_code, info.name) for info in tr_info_list], columns=['tr_code', 'name'])
+>>> data
+      tr_code             name
+0    opt10001         주식기본정보요청
+1    opt10059      종목별투자자기관별요청
+2    opt10087         시간외단일가요청
+3    opt50037       코스피200지수요청
+4    opt90005       프로그램매매추이요청
+..        ...              ...
+220  opw20013  계좌미결제청산가능수량조회요청
+221  opw20014     선옵실시간증거금산출요청
+222  opw20015    옵션매도주문증거금현황요청
+223  opw20016      신용융자 가능종목요청
+224  opw20017        신용융자 가능문의
+
+[225 rows x 2 columns]
+
+
+
+
+

OPT10001 TR 요청 전송 및 응답 처리 (싱글데이터)

+
>>> opt10001_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001")
+>>> opt10001_info
+KiwoomOpenApiPlusTrInfo('opt10001', '주식기본정보요청', 'STOCK', '', '1', '', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 6, 9001)], '주식기본정보', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('종목명', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('결산월', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('액면가', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('자본금', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('상장주식', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('신용비율', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('연중최고', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('연중최저', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('시가총액', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('시가총액비중', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('외인소진률', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('대용가', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('매출액', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('영업이익', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('당기순이익', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250최고', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250최저', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('시가', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('상한가', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('하한가', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('기준가', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('예상체결가', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('예상체결수량', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250최고가일', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250최고가대비율', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250최저가일', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250최저가대비율', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('현재가', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('대비기호', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('전일대비', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('등락율', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('거래량', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대비', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('액면가단위', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('유통주식', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('유통비율', 840, 20, 1684)], '', [])
+
+>>> opt10001_info.inputs
+[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 6, 9001)]
+
+>>> opt10001_info.single_outputs
+[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 389), KiwoomOpenApiPlusTrInfo.Field('종목명', 20, 50, 302), KiwoomOpenApiPlusTrInfo.Field('결산월', 40, 20, 315), KiwoomOpenApiPlusTrInfo.Field('액면가', 60, 20, 310), KiwoomOpenApiPlusTrInfo.Field('자본금', 80, 20, 309), KiwoomOpenApiPlusTrInfo.Field('상장주식', 100, 20, 312), KiwoomOpenApiPlusTrInfo.Field('신용비율', 120, 20, 329), KiwoomOpenApiPlusTrInfo.Field('연중최고', 140, 20, 1006), KiwoomOpenApiPlusTrInfo.Field('연중최저', 160, 20, 1009), KiwoomOpenApiPlusTrInfo.Field('시가총액', 180, 20, 311), KiwoomOpenApiPlusTrInfo.Field('시가총액비중', 200, 20, 336), KiwoomOpenApiPlusTrInfo.Field('외인소진률', 220, 20, 314), KiwoomOpenApiPlusTrInfo.Field('대용가', 240, 20, 308), KiwoomOpenApiPlusTrInfo.Field('PER', 260, 20, 1600), KiwoomOpenApiPlusTrInfo.Field('EPS', 280, 20, 1604), KiwoomOpenApiPlusTrInfo.Field('ROE', 300, 20, 1630), KiwoomOpenApiPlusTrInfo.Field('PBR', 320, 20, 1601), KiwoomOpenApiPlusTrInfo.Field('EV', 340, 20, 1608), KiwoomOpenApiPlusTrInfo.Field('BPS', 360, 20, 1605), KiwoomOpenApiPlusTrInfo.Field('매출액', 380, 20, 1610), KiwoomOpenApiPlusTrInfo.Field('영업이익', 400, 20, 1611), KiwoomOpenApiPlusTrInfo.Field('당기순이익', 420, 20, 1614), KiwoomOpenApiPlusTrInfo.Field('250최고', 440, 20, 1000), KiwoomOpenApiPlusTrInfo.Field('250최저', 460, 20, 1003), KiwoomOpenApiPlusTrInfo.Field('시가', 480, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 500, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 520, 20, 18), KiwoomOpenApiPlusTrInfo.Field('상한가', 540, 20, 305), KiwoomOpenApiPlusTrInfo.Field('하한가', 560, 20, 306), KiwoomOpenApiPlusTrInfo.Field('기준가', 580, 20, 307), KiwoomOpenApiPlusTrInfo.Field('예상체결가', 600, 20, 10023), KiwoomOpenApiPlusTrInfo.Field('예상체결수량', 620, 20, 10024), KiwoomOpenApiPlusTrInfo.Field('250최고가일', 640, 20, 1001), KiwoomOpenApiPlusTrInfo.Field('250최고가대비율', 660, 20, 1002), KiwoomOpenApiPlusTrInfo.Field('250최저가일', 680, 20, 1004), KiwoomOpenApiPlusTrInfo.Field('250최저가대비율', 700, 20, 1005), KiwoomOpenApiPlusTrInfo.Field('현재가', 720, 20, 10), KiwoomOpenApiPlusTrInfo.Field('대비기호', 740, 20, 25), KiwoomOpenApiPlusTrInfo.Field('전일대비', 760, 20, 11), KiwoomOpenApiPlusTrInfo.Field('등락율', 780, 20, 12), KiwoomOpenApiPlusTrInfo.Field('거래량', 800, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대비', 820, 20, 30), KiwoomOpenApiPlusTrInfo.Field('액면가단위', 840, 20, 796), KiwoomOpenApiPlusTrInfo.Field('유통주식', 840, 20, 1683), KiwoomOpenApiPlusTrInfo.Field('유통비율', 840, 20, 1684)]
+
+>>> opt10001_info.multi_outputs
+[]
+
+
+
>>> request_name = "주식기본정보요청"  # 사용자 구분명, 구분가능한 임의의 문자열
+>>> tr_code = "opt10001"
+>>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
+>>> inputs = {
+...    "종목코드": "005930",  # 삼성전자 종목코드
+... }
+
+>>> output = {}
+
+>>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
+...     names = event.single_data.names
+...     values = event.single_data.values
+...     for name, value in zip(names, values):
+...         output[name] = value
+
+>>> output
+{'종목코드': '005930', '종목명': '삼성전자', '결산월': '12', '액면가': '100', '자본금': '7780', '상장주식': '5969783', '신용비율': '+0.12', '연중최고': '+79800', '연중최저': '-71200', '시가총액': '4417639', '시가총액비중': '', '외인소진률': '+52.09', '대용가': '57170', 'PER': '19.27', 'EPS': '3841', 'ROE': '10.0', 'PBR': '1.88', 'EV': '5.09', 'BPS': '39406', '매출액': '2368070', '영업이익': '359939', '당기순이익': '264078', '250최고': '+86400', '250최저': '-68300', '시가': '+74300', '고가': '+74600', '저가': '+73400', '상한가': '+95200', '하한가': '-51400', '기준가': '73300', '예상체결가': '-0', '예상체결수량': '0', '250최고가일': '20210202', '250최고가대비율': '-14.35', '250최저가일': '20211013', '250최저가대비율': '+8.35', '현재가': '+74000', '대비기호': '2', '전일대비': '+700', '등락율': '+0.95', '거래량': '12730034', '거래대비': '-71.74', '액면가단위': '원', '유통주식': '4459119', '유통비율': '74.7'}
+
+
+
+
+

OPT10081 TR 요청 전송 및 응답 처리 (멀티데이터)

+
>>> opt10081_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10081")
+>>> opt10081_info
+KiwoomOpenApiPlusTrInfo('opt10081', '주식일봉차트조회요청', 'SCHART', '', '1', '3003', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('기준일자', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 40, 20, 9055)], '주식일봉차트', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001)], '주식일봉차트조회', [KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('현재가', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('거래량', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대금', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('일자', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('시가', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('수정비율', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('대업종구분', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('소업종구분', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('종목정보', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('수정주가이벤트', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('전일종가', 280, 20, 346)])
+
+>>> opt10081_info.inputs
+[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('기준일자', 20, 20, 9004), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 40, 20, 9055)]
+
+>>> opt10081_info.single_outputs
+[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001)]
+
+>>> opt10081_info.multi_outputs
+[KiwoomOpenApiPlusTrInfo.Field('종목코드', 0, 20, 9001), KiwoomOpenApiPlusTrInfo.Field('현재가', 0, 20, 10), KiwoomOpenApiPlusTrInfo.Field('거래량', 40, 20, 13), KiwoomOpenApiPlusTrInfo.Field('거래대금', 60, 20, 14), KiwoomOpenApiPlusTrInfo.Field('일자', 80, 20, 22), KiwoomOpenApiPlusTrInfo.Field('시가', 100, 20, 16), KiwoomOpenApiPlusTrInfo.Field('고가', 120, 20, 17), KiwoomOpenApiPlusTrInfo.Field('저가', 140, 20, 18), KiwoomOpenApiPlusTrInfo.Field('수정주가구분', 160, 20, 3502), KiwoomOpenApiPlusTrInfo.Field('수정비율', 180, 20, 3503), KiwoomOpenApiPlusTrInfo.Field('대업종구분', 200, 20, 317), KiwoomOpenApiPlusTrInfo.Field('소업종구분', 220, 20, 318), KiwoomOpenApiPlusTrInfo.Field('종목정보', 240, 20, 370), KiwoomOpenApiPlusTrInfo.Field('수정주가이벤트', 260, 20, 3501), KiwoomOpenApiPlusTrInfo.Field('전일종가', 280, 20, 346)]
+
+
+
>>> import datetime
+
+>>> date = datetime.datetime.now().strftime("%Y%m%d")
+>>> date
+'20220206'
+
+
+
>>> request_name = "주식일봉차트조회요청"  # 사용자 구분명, 구분가능한 임의의 문자열
+>>> tr_code = "opt10081"
+>>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
+>>> inputs = {
+...     "종목코드": "005930",  # 삼성전자 종목코드
+...     "기준일자": "20220206",  # 가장 최근 날짜의 YYYYMMDD 포맷
+...     "수정주가구분": "0",  # 0:일반주가, 1:수정주가
+... }
+
+>>> data_list = []
+
+>>> for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
+...     columns = event.multi_data.names
+...     records = [values.values for values in event.multi_data.values]
+...     data = pd.DataFrame.from_records(records, columns=columns)
+...     data_list.append(data)
+
+>>> data = pd.concat(data_list, axis=0).reset_index(drop=True)
+>>> data
+        종목코드    현재가       거래량     거래대금        일자     시가     고가     저가 수정주가구분  \
+0     005930  74000  12730034   941413  20220204  74300  74600  73400
+1             73300  17744721  1314506  20220203  74900  74900  73300
+2             73300  21367447  1552586  20220128  71300  73700  71200
+3             71300  22274777  1603685  20220127  73800  74000  71300
+4             73300  12976730   955547  20220126  73900  74400  73100
+...      ...    ...       ...      ...       ...    ...    ...    ...    ...
+9797           8010      4970        1  19850109   8240   8240   7950
+9798           8300     12930        4  19850108   8400   8400   8300
+9799           8410     11810        3  19850107   8400   8500   8390
+9800           8390      1660        0  19850105   8400   8440   8390
+9801           8450      1710        0  19850104   8500   8500   8450
+
+    수정비율 대업종구분 소업종구분 종목정보 수정주가이벤트 전일종가
+0
+1
+2
+3
+4
+...   ...   ...   ...  ...     ...  ...
+9797
+9798
+9799
+9800
+9801
+
+[9802 rows x 15 columns]
+
+
+
+
+

조건검색 조건식 설정 불러오기

+
>>> entrypoint.IsConditionLoaded()
+False
+>>> entrypoint.EnsureConditionLoaded()
+1
+>>> entrypoint.IsConditionLoaded()
+True
+
+
+
+
+

불러온 조건식 목록 확인

+
>>> condition_name_list = entrypoint.GetConditionNameListAsList()
+>>> condition_name_list
+[(0, '대형 저평가 우량주'), (1, '중소형 저평가주')]
+
+
+
+
+

조건식 단순 검색

+
>>> condition_name = "대형 저평가 우량주"
+>>> condition_met_code_list, condition_met_code_list_info = entrypoint.GetCodeListByCondition(condition_name, with_info=True)
+
+>>> condition_met_code_list
+['000240', '001800', '001880', '003230', '003550', '004000', '006040', '006390', '006650', '007700', '009970', '011780', '014830', '020000', '021240', '025540', '030520', '033290', '033780', '036830', '042420', '056190', '057050', '060150', '064960', '069080', '081660', '095660', '096530', '110790', '111770', '137310', '161390', '161890', '185750', '192080', '192400', '200130', '243070', '271560', '284740', '285130', '294870', '300720', '950130']
+
+>>> condition_met_code_list_info  # same as entrypoint.GetStockQuoteInfoAsDataFrame(condition_met_code_list)
+      종목코드        종목명      현재가     기준가   전일대비 전일대비기호     등락율      거래량    거래대금  \
+0   000240     한국앤컴퍼니   +13500   13400   +100      2   +0.75    56484     760
+1   001800     오리온홀딩스   +14600   14250   +350      2   +2.46    69827    1008
+2   001880       DL건설   -27950   28050   -100      5   -0.36    20925     583
+3   003230       삼양식품   +91300   90000  +1300      2   +1.44    58660    5289
+4   003550         LG   +76300   74600  +1700      2   +2.28   249415   18925
+..     ...        ...      ...     ...    ...    ...     ...      ...     ...
+40  284740      쿠쿠홈시스   +36700   35900   +800      2   +2.23    30134    1102
+41  285130      SK케미칼  +130500  129500  +1000      2   +0.77    58032    7544
+42  294870  HDC현대산업개발   +15600   14600  +1000      2   +6.85  3145356   49106
+43  300720      한일시멘트   +19250   18750   +500      2   +2.67   159419    3021
+44  950130     엑세스바이오   -18400   22400  -4000      5  -17.86  5877689  119649
+
+    체결량  ...    ELW만기일 미결제약정 미결제전일대비 이론가 내재변동성 델타 감마 쎄타 베가 로
+0   5549  ...  00000000
+1     +1  ...  00000000
+2    369  ...  00000000
+3     +2  ...  00000000
+4   +100  ...  00000000
+..   ...  ...       ...   ...     ...  ..   ... .. .. .. .. ..
+40    -3  ...  00000000
+41    -1  ...  00000000
+42   -25  ...  00000000
+43    -4  ...  00000000
+44   -36  ...  00000000
+
+[45 rows x 63 columns]
+
+
+
+
+

GRPC 스트림 처리 관련 유틸리티 함수 (데모 목적)

+
>>> import contextlib
+>>> import threading
+>>> import warnings
+
+>>> import grpc
+
+>>> @contextlib.contextmanager
+... def warn_on_rpc_error_context():
+...     try:
+...         yield
+...     except grpc.RpcError as e:
+...         warnings.warn(str(e))
+
+>>> def warn_on_rpc_error(stream):
+...     with warn_on_rpc_error_context():
+...         for event in stream:
+...             yield event
+
+>>> def cancel_after(stream, after):
+...     timer = threading.Timer(after, stream.cancel)
+...     timer.start()
+...     return warn_on_rpc_error(stream)
+
+
+
+
+

조건식 실시간 검색

+
>>> condition_name = "중소형 저평가주"
+>>> stream = entrypoint.GetCodeListByConditionAsStream(condition_name)
+
+>>> condition_met_code_list = []
+>>> data_list = []
+
+>>> for event in cancel_after(stream, 10):
+...     if event.name == "OnReceiveTrCondition":
+...         initially_included_code_list = event.arguments[1].string_value
+...         initially_included_code_list = initially_included_code_list.rstrip(';').split(';') if initially_included_code_list else []
+...         condition_met_code_list.extend(initially_included_code_list)
+...     elif event.name == "OnReceiveRealCondition":
+...         code = event.arguments[0].string_value
+...         condition_type = event.arguments[1].string_value
+...         if condition_type == "I":
+...             code_inserted = code
+...             condition_met_code_list.append(code_inserted)
+...         elif condition_type == "D":
+...             code_deleted = code
+...             condition_met_code_list.remove(code_deleted)
+...     elif event.name == "OnReceiveTrData":
+...         columns = event.multi_data.names
+...         records = [values.values for values in event.multi_data.values]
+...         data = pd.DataFrame.from_records(records, columns=columns)
+...         data_list.append(data)
+
+>>> condition_met_code_list
+['900290', '900310', '900340', '002170', '017890', '023600', '036190', '037710', '049430', '073560', '140910', '187870', '192440', '210540', '225220', '263690', '352700', '950190', '900280', '900250']
+
+>>> data_list
+[]
+
+
+
+
+

계좌정보 확인

+
>>> account_list = entrypoint.GetAccountList()
+>>> account_list
+['8014526011']
+
+>>> first_account_no = entrypoint.GetFirstAvailableAccount()
+>>> first_account_no
+'8014526011'
+
+
+
+
+

주문 요청 (삼성전자 시장가 매수)

+
>>> request_name = "삼성전자 1주 시장가 신규 매수"  # 사용자 구분명, 구분가능한 임의의 문자열
+>>> screen_no = "0001"  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
+>>> account_no = "8014526011"  # 계좌번호 10자리, 여기서는 계좌번호 목록에서 첫번째로 발견한 계좌번호로 매수처리
+>>> order_type = 1  # 주문유형, 1:신규매수
+>>> code = "005930"  # 종목코드, 앞의 삼성전자 종목코드
+>>> quantity = 1  # 주문수량, 1주 매수
+>>> price = 0  # 주문가격, 시장가 매수는 가격 설정 의미 없으므로 기본값 0 으로 설정
+>>> quote_type = "03"  # 거래구분, 03:시장가
+>>> original_order_no = ""  # 원주문번호, 주문 정정/취소 등에서 사용
+
+>>> stream = entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no)
+
+>>> for event in warn_on_rpc_error(stream):
+...     if event.name == "OnReceiveTrData":
+...         order_no = event.single_data.values[0]
+...     elif event.name == "OnReceiveChejanData":
+...         gubun = event.arguments[0].string_value
+...         data = dict(zip(event.single_data.names, event.single_data.values))
+...         if gubun == "0":
+...             status = data["주문상태"]
+...             if status == "접수":
+...                 pass
+...             elif status == "체결":
+...                 orders_filled = data["체결량"]
+...                 orders_left = data["미체결수량"]
+...             elif status == "확인":
+...                 org_order_no = data["원주문번호"]
+...                 assert original_order_no == org_order_no
+...         elif gubun in ["1", "4"]:
+...             stocks = data["보유수량"]
+
+
+
+
+

키움증권의 실시간 데이터 메타 정보 확인

+
>>> from koapy import KiwoomOpenApiPlusRealType
+
+
+
>>> realtype_list = KiwoomOpenApiPlusRealType.get_realtype_info_list()
+
+
+
>>> realtype_descs = [realtype.desc for realtype in realtype_list]
+>>> realtype_descs
+['주식시세', '주식체결', '주식상하한', '주식우선호가', '주식호가잔량', '주식시간외호가', '주식당일거래원', 'ETF NAV', 'ELW 지표', 'ELW 이론가', '주식예상체결', '주식종목정보', '임의연장정보', 'ECN주식시세', 'ECN주식체결', 'ECN주식우선호가', 'ECN주식호가잔량', 'ECN주식시간외호가', 'ECN주식당일거래원', '시간외종목정보', '주식거래원', '주식거래원(1LINE)', '종목별프로그램매매', 'VI정적예상가', 'VI발동/해제-종목별', '종목별프로그램매매2', '종목투자자(잠정)', '종목투자자(거래소)', '대주가능수량', '선물옵션우선호가', '선물시세', '선물호가잔량', '선물이론가', '선물기초자산시세', '실시간상하한가', '옵션시세', '옵션호가잔량', '옵션이론가', '주식옵션시세', '주식옵션호가잔량', '주식옵션이론가', '업종지수', '업종등락', '자체업종지수', '예상업종지수', '시황/뉴스', '환률', '장시작시간', '투자자ticker', '상하한가폭변경', 'VI발동/해제', '투자자별매매', '프로그램매매', '해외시세', '주문체결', '파생잔고', '현물잔고', '예수금', '해외주문체결', '해외잔고', '순간체결량', '주문체결서버상태', '증거금', 'CFD주문', 'CFD체결', 'CFD마진콜경고', 'CFD입출고', '자유포멧', '조건검색', '일반신호', '리얼잔고', '해외리얼잔고', '리얼잔고총합', '해외잔고총합', '스톱로스', '선물옵션합계', '스톱주문', 'CFD주문체결', 'CFD리얼잔고', 'CFD리얼잔고총합', '모니터링 실시간LOG', '주식선물호가잔량', '실시간증거금', 'X-Ray순간체결량', '매입인도체결', '매입인도호가', '코넥스경매매체결', '데이터셋실시간', '홍콩체결', '홍콩시세', '홍콩호가잔량', '홍콩단일가시세', '홍콩업종지수', '홍콩실시간상하한가', '수동자동주문', '자동주문결과', 'TS고저변경', '잔고편입', '기준가변경', '멀티차단', '잔고청산삭제', '후강퉁체결', '후강퉁시세', '후강퉁호가잔량', '후강퉁단일가시세', '후강퉁업종지수', '미체결통보시스템', '채널K실시간티커', '빅데이터종목1분', '빅데이터종목10분', '빅데이터종목1시간', '빅데이터종목당일', '빅데이터뉴스', '신호관리자투자정보', '빅데이터급상승', '빅데이터종목30초', '알-종목포착이탈', '알-매도감시시작', '알-매도감시포착', '알-주문결과', '알-청산시작', '알-청산완료', '알-감시시작', '알-내조건식수정', '알-주문조건수정', '알-제한여부', '알-멀티차단', '알-TS변경', '알-모의주문체결', '알-모의현물잔고', '알-모의 주문체결', '알-모의 리얼잔고', '알-모의리얼잔고총합', '채권체결', '채권호가잔량', '소액채권체결', '소액채권호가잔량', 'CME시세', 'CME미결제약정', 'CME호가잔량', 'EUF시세', 'EUF호가잔량', 'EUREX시세', 'EUREX호가', '배치데이터갱신', '종목마스터갱신', '해외주식주문', '해외주식체결', '해외실시간잔고조회', '미국입출고', '미국종목변경', 'CME/EUREX주문', 'CME/EUREX체결', 'CME배치', 'EUREX배치', 'CME미체결', 'CME실시간잔고', 'CME잔고합', '분할반복주문']
+
+>>> realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_name("주식시세")
+>>> realtype_info
+KiwoomOpenApiPlusRealType('0A', '주식시세', 21, [10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732])
+
+>>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세")
+>>> fid_list
+[10, 11, 12, 27, 28, 13, 14, 16, 17, 18, 25, 26, 29, 30, 31, 32, 311, 822, 567, 568, 732]
+
+>>> KiwoomOpenApiPlusRealType.Fid.get_name_by_fid(10)
+'현재가'
+
+>>> fid_names = KiwoomOpenApiPlusRealType.get_field_names_by_realtype_name("주식시세")
+>>> fid_names
+['현재가', '전일대비', '등락율', '매도호가', '매수호가', '누적거래량', '누적거래대금', '시가', '고가', '저가', '전일대비기호', '거래량전일대비', '거래대금증감', '전일거래량대비율', '거래회전율', '거래비용', '시가총액', '822', '567', '568', '732']
+
+
+
+
+

실시간 데이터 요청 (삼성전자 주식시세 실시간 데이터 요청)

+
>>> code_list = ["005930"]
+>>> fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name("주식시세")
+>>> opt_type = "0"  # 기존 화면에 추가가 아니라 신규 생성
+
+>>> stream = entrypoint.GetRealDataForCodesAsStream(
+...     code_list,
+...     fid_list,
+...     opt_type,
+...     screen_no=None,  # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당
+...     infer_fids=True,  # True 로 설정 시 주어진 fid_list 를 고집하지 말고 이벤트 처리 함수의 인자로 전달받는 실시간데이터 이름에 따라 유연하게 fid_list 를 추론
+...     readable_names=True,  # True 로 설정 시 각 fid 마다 숫자 대신 읽을 수 있는 이름으로 변환하여 반환
+...     fast_parse=False,  # True 로 설정 시 이벤트 처리 함수내에서 데이터 값 읽기 시 GetCommRealData() 함수 호출 대신, 이벤트 처리 함수의 인자로 넘어오는 데이터를 직접 활용, infer_fids 가 True 로 설정된 경우만 유의미함
+... )
+
+>>> for event in cancel_after(stream, 10):
+...     if event.name == "OnReceiveRealData":
+...         data = dict(zip(event.single_data.names, event.single_data.values))
+...         if "현재가" in data:
+...             current_price = data["현재가"]
+
+
+
+
+

사용 종료 후 엔트리포인트 객체 리소스 해제 (연결 해제 및 서버 어플리케이션 종료)

+

직접 close() 메소드 호출:

+
>>> entrypoint.close()
+
+
+

혹은 처음부터 컨텍스트 매니저 형태로 리소스 관리:

+
>>> with KiwoomOpenApiPlusEntrypoint() as entrypoint:
+...     entrypoint.EnsureConnected()
+...     ...
+
+
+
+
+
+

Installation

+

대표적으로 아래와 같이 PyPI 를 통해서 설치가 가능합니다:

+
$ pip install koapy
+
+
+

만약에 개발 환경을 구축하고자 하는 경우에는 poetry 를 활용해 구성합니다.

+
$ # Install poetry (here using pipx)
+$ python -m pip install pipx
+$ python -m pipx ensurepath
+$ pipx install poetry
+
+$ # Clone repository
+$ git clone https://github.com/elbakramer/koapy.git
+$ cd koapy/
+
+$ # Install dependencies and hooks
+$ poetry install
+$ poetry run pre-commit install
+
+
+

이외에 자세한 설치방법과 관련해서는 Installation 문서를 참고하세요.

+
+
+

Usage

+

설치 이후 일반적인 사용법에 대해서는 Usage 를 참고하세요.

+

추가적으로 사용법과 관련된 다양한 예시들은 examples 폴더 및 notebooks_ipynb 폴더에서도 확인 가능합니다. +혹시나 notebooks_ipynb 폴더의 .ipynb 파일들을 Github 을 통해서 보는데 문제가 있는 경우, +해당 노트북 주소를 nbviewer 에 입력하여 확인해 보세요.

+

현재 알파 단계이기 때문에 많은 기능들이 실제로 문제없이 동작하는지 충분히 테스트되지 않았습니다. +만약에 실전 트레이딩에 사용하려는 경우 자체적으로 충분한 테스트를 거친 후 사용하시기 바랍니다.

+

개발자는 라이브러리 사용으로 인해 발생하는 손실에 대해 어떠한 책임도 지지 않습니다.

+

또한 알파 단계에서 개발이 진행되면서 라이브러리의 구조가 계속 급격하게 변경될 수 있으니 참고 바랍니다.

+
+
+

Features

+

KOAPY 는 아래와 같은 방향성을 가지고 개발되었습니다.

+
+

GUI 어플리케이션만으로 제한되지 않는 다양한 사용성

+

일반적으로 인터넷 등지에서 접하기 쉬운 관련 예시들을 처음으로 따라가다 보면, 자기도 +모르는 사이에 Qt 기반 어플리케이션을 하나 만들고, 버튼을 하나 추가하고, 이후 모든 +기능들을 죄다 해당 버튼을 클릭 시 작동하는 콜백 함수 하나에 쑤셔 넣고 있는.. 자신을 +발견하게 되더군요.

+
# https://wikidocs.net/4240
+
+import sys
+
+from PyQt5.QtWidgets import *
+from PyQt5.QtGui import *
+from PyQt5.QAxContainer import *
+
+class MyWindow(QMainWindow):
+    def __init__(self):
+        super().__init__()
+        self.setWindowTitle("PyStock")
+        self.setGeometry(300, 300, 300, 150)
+
+        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
+
+        btn1 = QPushButton("Login", self)
+        btn1.move(20, 20)
+        btn1.clicked.connect(self.btn1_clicked)
+
+        btn2 = QPushButton("Check state", self)
+        btn2.move(20, 70)
+        btn2.clicked.connect(self.btn2_clicked)
+
+    def btn1_clicked(self):
+        ret = self.kiwoom.dynamicCall("CommConnect()")
+
+    def btn2_clicked(self):
+        if self.kiwoom.dynamicCall("GetConnectState()") == 0:
+            self.statusBar().showMessage("Not connected")
+        else:
+            self.statusBar().showMessage("Connected")
+
+if __name__ == "__main__":
+    app = QApplication(sys.argv)
+    myWindow = MyWindow()
+    myWindow.show()
+    app.exec_()
+
+
+

사실 기반 라이브러리가 애초에 OCX 형태로서 제공되는 것도 있고, 다른 여러 가지 이유들로 +인해 이처럼 GUI 어플리케이션 형태로 개발을 하는 것이 자연스러운 흐름이고 절대 +잘못되었다고 생각되진 않습니다.

+

다만 이러한 GUI 환경이 일반적으로 Python 에서 REPL 혹은 Jupyter Notebook 등을 통해서 +인터랙티브하게 결과 값들을 확인해가면서 조금씩 개발해 나가던 것과는 거리가 멀어지면서 +결론적으로 생산성이 떨어지게 되는 건 아닌가 하는 생각이 들었고, 그로 인해 KOAPY 의 +기본적인 인터페이스는 기반이 되는 Qt 환경을 개발자가 직접적으로 고려하진 않으면서도 +기능은 쉽게 사용해 볼 수 있게 끔 하는 게 좋겠다고 생각했습니다.

+

따라서 KOAPY 의 기본적인 디자인은 우선 외적으로 봤을 때 이게 내부적으로는 Qt 같은 +환경하에서 돌아간다는 것을 바로 알아챌 순 없게 끔 되어 있습니다. 그리고 기본적인 +기능들을 이용하는 데에 있어서도 버튼 클릭 등의 이벤트에 기반한 호출보단 일반적인 함수 +호출과 같은 명령형 프로그래밍이 가능하도록 디자인 하였으며, 문서에서도 해당 사용 +시나리오들을 중점적으로 먼저 소개하고 있습니다.

+
from koapy import KiwoomOpenApiPlusEntrypoint
+
+with KiwoomOpenApiPlusEntrypoint() as entrypoint:
+    entrypoint.EnsureConnected()
+    is_connected = entrypoint.IsConnected()
+    print(is_connected)
+
+
+

결론적으로 PyQt5 혹은 PySide2 를 기반한 GUI 환경에 얽매일 필요 없이 일반적인 +라이브러리처럼 가져다 활용할 수 있으며, 여전히 GUI 기반 어플리케이션 개발이 필요하다면 +내부적으로 사용되는 요소들을 통해 직접 GUI 방향으로 개발을 할 수도 있습니다.

+
from koapy.compat.pyside2.QtWidgets import QApplication, QMainWindow
+from koapy import KiwoomOpenApiPlusQAxWidget
+
+class MyWindow(QMainWindow):
+    def __init__(self):
+        super().__init__()
+
+        self.kiwoom = KiwoomOpenApiPlusQAxWidget()
+        ...
+
+
+
+
+

함수 호출등의 과정에서 일반적인 Python 의 관습을 크게 해치지 않는 매끄러운 인터페이스 구성

+

Qt 를 통해서 COM/OLE/OCX 객체의 메서드를 호출하려면 dynamicCall 함수를 활용해야 합니다.

+

해당 dynamicCall 함수는 호출하고자 하는 메서드의 프로토타입을 문자열 형태 인자로서 +입력하도록 되어있는데, 단순하게는 매번 메서드를 호출하고자 할 때마다 해당 메서드의 +프로토타입이 어떻게 생겼는지를 문서 등을 참고하고 일일이 적어 넣어줘야 할 수 있습니다.

+
control = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
+control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code)
+
+
+

그 다음으로 보다 나은 방식으로는 이러한 프로토타입을 모든 함수들에 대해서 확인해서 +간단한 래퍼 함수들을 만들어두고 활용하는 게 있겠죠.

+
def SetInputValue(name, value):
+    return control.dynamicCall("SetInputValue(const QString&, const QString&)", name, value)
+
+
+

일반적으로는 이런 방식들로도 충분히 사용하는데 무리가 없으리라 생각됩니다만 +개인적으로는 위와 같은 접근 방식에서 몇 가지 우려되는 점들이 신경이 쓰였습니다.

+
    +
  • 프로토타입을 입력하거나 래퍼 함수들을 만들어 넣는 과정에서 발생할 수 있는 휴먼에러

  • +
  • 래퍼 함수들을 만들어 놓았더라도 추후 함수의 목록 혹은 특정 함수의 프로토타입에서 +변경이 발생하는 경우 매번 직접적인 대응이 필요함

  • +
+

따라서 KOAPY 에서는 이러한 지원 함수 목록 및 함수별 프로토타입 정보 확인, 그리고 +이것들을 활용해 특정 메서드를 호출하는 과정까지를 어떻게 프로그래밍적으로 대응할 수 +없을까를 고민했고, 현재는 OpenAPI+ OCX 의 TypeLib 정보를 읽어와 메서드들을 동적으로 +생성하도록 구현해 위에서 우려했던 점들을 해결했습니다.

+

최종적으론 컨트롤 함수 호출 시 매뉴얼의 명세에 적혀있는 형태 그대로 Python 함수였던 +것처럼 호출이 가능하며, 이후는 KOAPY 가 유연하게 처리합니다. 매번 명세에 맞게 +dynamicCall 함수의 인자를 적어 넣거나, 모든 존재하는 함수에 대해 미리 래퍼 함수를 +손 아프게 만들어놓을 필요가 없습니다.

+
control = KiwoomOpenApiPlusQAxWidget()
+control.SetInputValue("종목코드", code)
+
+
+
+
+

이벤트 처리 및 비동기 프로그래밍 관련 복잡하지 않은 인터페이스 제공

+

비동기 프로그래밍은 일반적으로 어렵습니다. 특히 OpenAPI+ 및 KOAPY 의 경우를 예로 +들어보면 아래와 같은 고민해 볼 만한 부분들이 있습니다.

+
    +
  • 여러 요청에 대한 응답 결과들을 이벤트 타입별 하나씩의 통로로 처리하기 때문에 그들 +간의 교통정리부터 필요합니다.

  • +
  • 콜백 함수 내에서 OpenAPI+ 가 기대하는 혹은 가이드하는 방식에 맞춰서 처리해 주어야 +하는 특정 단계 혹은 프로세스가 존재하며 이를 적절히 대응해 주어야 합니다.

  • +
  • 콜백 함수에서 받은 결과를 최종적으로 해당 결과가 필요한 곳으로 (일반적으론 요청한 +대상에게로) 잘 전달해 주어야 합니다.

  • +
+

KOAPY 에서는 위의 문제들을 나름의 방식대로 고민하였고 문제들을 해결하여 더 쉽고 나은 +인터페이스를 사용자에게 제공하고 있습니다.

+

구체적으로 예를 하나 들자면, 일반적인 요청-응답 과정에서 내부적으로 gRPC +클라이언트-서버 관계를 만들어 요청자가 gRPC 를 통해 특정 요청을 전달하면, 이후 gRPC +서버에서는 해당 요청에 대한 응답들만 추려서 결과를 요청자측에 스트림 형태로 전달하도록 +디자인되어 있는데요. 여기서 교통정리 및 결과 전달 문제가 자연스럽게 해결되며 부수적으로 +사용자 입장에서는 직접 콜백 함수를 다루기보다는 간접적으로 스트림을 +(for 문을 활용하여) 다룸으로써 더 쉽게 비동기 프로그래밍이 필요한 기능들을 사용할 +수 있는 이점이 있습니다.

+

PySide2 를 통한 직접적인 방식:

+
# 컨트롤 객체
+control = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
+
+# 이벤트 시그널
+on_receive_tr_data_signal = SIGNAL("OnReceiveTrData(const QString&, const QString&, const QString&, const QString&, const QString&, int, const QString&, const QString&, const QString&)")
+
+# 이벤트 콜백 함수
+def on_receive_tr_data(screen_no, request_name, tr_code, record_name, prev_next, data_length, error_code, message, splmmsg):
+    handle_event(...)
+
+    # 이벤트 처리 후 필요하다면 등록된 콜백 함수 제거
+    if should_disconnect:
+        control.disconnect(on_receive_tr_data_signal, on_receive_tr_data)
+
+# 이벤트 시그널에 콜백 함수 연결
+control.connect(on_receive_tr_data_signal, on_receive_tr_data)
+
+# TR 입력값 설정
+control.dynamicCall("SetInputValue(const QString&, const QString&)", ..., ...)
+...
+
+# TR 요청
+err_code = control.dynamicCall(
+    "CommRqData(const QString&, const QString&, int, const QString&)",
+    request_name,
+    tr_code,
+    prev_next,
+    screen_no,
+)
+
+
+

KOAPY 방식:

+
# TR 요청 후 이벤트가 스트림 형태로 반환
+for event in entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs):
+    handle_event(event)
+
+
+

결론적으로는 사용자가 이벤트 처리 및 비동기 프로그래밍에 익숙하지 않더라도 그보다 +비교적 쉬운 인터페이스를 통해 관련 기능들을 활용할 수 있습니다.

+

더 나아가서는 가장 간단한 로그인 처리부터 TR/실시간 데이터 처리, 그리고 주문처리까지 +다양한 시나리오에 대한 기본 이벤트 처리 로직을 구현해 제공해 사용자들이 비동기 +프로그래밍이 필요한 기능 중 주로 사용되는 기능들에 쉽게 접근할 수 있도록 했습니다.

+
stream = entrypoint.LoginCall()
+stream = entrypoint.TransactionCall(request_name, tr_code, screen_no, inputs)
+stream = entrypoint.RealCall(screen_no, codes, fids, opt_type)
+stream = entrypoint.OrderCall(request_name, screen_no, account_no, order_type, code, quantity, price, quote_type, original_order_no)
+
+
+
+
+

여러 일반적인 시나리오들에 대한 다양한 기본 구현체들을 제공

+

KOAPY 에서는 일반적으로 자주 사용되는 기능들에 대해서 사용자들이 쉽게 접근할 수 있도록, +예를 들어 주식 기본정보 요청부터 일봉/분봉 등 시세 데이터 확인 그리고 예수금/잔고 확인 등등에 대해 미리 구현된 함수를 제공합니다.

+
stock_info = entrypoint.GetStockBasicInfoAsDict(stock_code)
+stock_chart_data = entrypoint.GetDailyStockDataAsDataFrame(stock_code)
+
+account_deposit = entrypoint.GetDepositInfo(account_no)
+account_evaluation = (
+    account_evaluation_summary,
+    account_evaluation_per_stock,
+) = entrypoint.GetAccountEvaluationStatusAsSeriesAndDataFrame(account_no)
+
+
+

이 중에 함수 호출 결과 중 테이블성 정보들은 pandas.DataFrame 타입으로 제공해 이후 분석 및 처리가 유용하게끔 했습니다.

+
+
+

개발과정에서 라이브러리 밖을 드나들 필요가 없도록 자주 확인이 필요한 여러가지 메타 정보들을 함께 제공

+

일반적으로 인터넷 등지에서 접하기 쉬운 관련 대부분 예시들은 사용자가 OpenAPI+ 에 대한 +여러 가지 메타정보들을 이미 다 알고 있다는 걸 가정하고, 아니면 적어도 외부 참고자료를 +확인하는 것을 가정하고 작성되어 있는 경우가 많습니다.

+

예를 들어 TR 의 입력과 출력 데이터 구조, 실시간 데이터별 FID 목록, 에러코드에 대한 +설명문 등이 이러한 메타정보들에 해당되는데요. 앞서 함수 호출 방식에서의 이슈와 비슷하게, +이러한 정보들을 매번 참고 자료를 확인하고 그에 맞춰 개발하는 방식에는 어느 정도 한계가 +있습니다.

+

따라서 KOAPY 에서는 이러한 정보들을 개발하는 과정에서 언어 내 라이브러리에서 바로 조회 +및 활용이 가능하도록 포함시켜 제공합니다. 이로 인해 일차적으로 사용자 입장에서는 매번 +매뉴얼 이나 KOAStudio 를 열어서 참고하고 이후 일일이 하나씩 하드코딩할 필요가 +없어졌습니다.

+
from koapy import KiwoomOpenApiPlusTrInfo
+tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code("opt10001")
+
+from koapy import KiwoomOpenApiPlusRealType
+realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_name("주식시세")
+
+from koapy import KiwoomOpenApiPlusError
+error_message = KiwoomOpenApiPlusError.get_error_message_by_code(-101)
+
+
+

덧붙여서 TR 관련 정보나 실시간 데이터 관련 정보들은 OpenAPI+ 가 설치되어 있는 경우 +해당 경로의 데이터를 참고해 동적으로 생성하도록 되어있는데요. 이로 인해 직접 하드코딩 +등을 했을 때 발생할 수 있는 이슈 없이, 매번 업데이트 시 변경된 내용이 바로바로 적용될 +수 있는 이점 또한 가지고 있습니다.

+
+
+

라이브러리 호환성으로 인해 특정 환경이 강제되는 것을 우회할 수 있도록 시스템 구성

+

키움증권의 OpenAPI+ 는 32bit 환경만 제공하고 있기 때문에 이를 사용하는 쪽도 자연스럽게 +32bit 기반이 되어야 합니다.

+

여기서는 Python 을 32bit 로 사용해야 하는 조건이 붙게 되는 것인데요. 몇몇 외부 +서드파티들에서는 더 이상 32bit 를 지원하지 않는 경우도 많아 다양한 서드파티 기능들과 +접목시키기에는 32bit 제약이 번거로운 점이 많습니다.

+

KOAPY 에서는 이를 해소하기 위해 gRPC 서버-클라이언트 형태의 구성을 잡아 서버에서는 +32bit 기반으로 OpenAPI+ 의 핵심 기능만 제공하도록 하고, 클라이언트에서는 이런 32bit +제약 없이 결과들을 받아서 이후 여러 서드파티 기능들과 함께 활용할 수 있도록 했습니다.

+

앞에서는 주로 32bit 제약을 가지고 이야기했지만 더 나아가서는 gRPC 의 많은 언어들에 +대한 확장성을 활용하여 Python 이외에 gRPC 에서 지원하는 다른 언어들로 클라이언트를 +작성해 사용하는 방식으로도 확장이 가능합니다.

+

또한 Python 에서 Qt 를 사용하기 위해서는 PyQt5 혹은 PySide2 를 사용해야 하는데요. +KOAPY 에서는 라이선스 등을 고려해서 기본값으로 PySide2 를 사용하도록 되어있지만, +사용자의 필요성에 따라 PySide2 대신 PyQt5 를 사용하려 할 때 쉽게 변경할 수 있도록 +qtpy 를 통해서 지원하고 있습니다.

+
+
+

키움증권의 OpenAPI+ 기능 자체 이외에 부수적으로 필요할만한 다양한 기능들을 추가로 제공

+

KOAPY 는 키움증권의 OpenAPI+ 핵심 기능 이외에 전체적인 개발 및 활용에 필요한 다양한 +부가기능들을 추가로 제공합니다.

+
    +
  • TR 호출 시 호출 횟수 제한 회피

  • +
  • KRX 거래소 휴장일 확인 (exchange_calendars API 활용)

  • +
  • 알람 및 메시지 기능 (discord.py API 활용)

  • +
+
+
+

라이브러리 뿐만 아니라 관련 기능들을 추가적인 코드 구현없이 쉽게 사용해볼 수 있도록 (+ 개념 증명 목적으로서) CLI 제공

+

굳이 Python 코드를 작성하지 않더라도 기본적인 기능들을 활용해 볼 수 있도록 여러 +커맨드를 포함하는 CLI 를 제공합니다.

+

CLI 를 활용하면 마켓별 코드 목록 확인, 주식 기본 정보 확인, 일봉/분봉 데이터 확인 및 +저장, 실시간 데이터 구독 등 다양한 기능들을 코드 구현 없이 사용할 수 있습니다.

+
$ koapy get stockcode --market=0
+$ koapy get stockinfo --code=005930
+$ koapy get daily --code=005930 --output=005930.xlsx
+$ koapy watch --code=005930 --realtype="주식시세"
+
+
+

서버도 CLI 커맨드로 쉽게 띄울 수 있습니다.

+
$ koapy serve
+
+
+
+
+
+

Licensing

+

KOAPY 는 다중 라이선스 방식으로 배포되며, +사용자는 자신의 의도 및 사용 방식에 따라 아래 라이선스 옵션들 중 하나를 선택해 사용할 수 있습니다.

+ +

라이선스 선택과 관련하여 추천하는 가이드라인은 아래와 같습니다.

+
+

MIT License

+
    +
  • 일반적인 사용자에게 알맞습니다.

  • +
  • 짧고 단순한 라이선스를 선호하시면 해당 라이선스를 선택하세요.

  • +
+
+
+

Apache License 2.0

+
    +
  • MIT 라이선스와 큰 차이는 없지만, 특허와 관련해서 명시적인 허가조항이 있습니다.

  • +
  • 추후 특허권 침해 소송이 우려되는 경우 MIT 라이선스 대신에 선택하시면 됩니다.

  • +
+
+
+

GNU General Public License v3.0 or later

+
    +
  • FSF/GPL 이 추구하는 Copyleft 의 가치를 따르신다면 선택 가능한 옵션중 하나입니다.

  • +
  • 이외에 backtrader 관련 기능들을 활용하시는 경우, KOAPY 는 반드시 GPLv3+ 로만 배포되어야 합니다.

  • +
  • 구체적으로 koapy.backtrader 모듈 하위의 기능들을 사용한다면 GPLv3+ 배포 조건에 해당됩니다.

  • +
  • 이것은 backtrader 가 GPLv3+ 로 배포되고 있으며, +해당 라이선스의 요구사항에 따라 그것을 사용하는 소프트웨어 또한 GPLv3+ 로 배포되어야 하기 때문입니다.

  • +
+

각 라이선스의 허가 및 요구사항과 관련해서 쉽게 정리된 내용은 tl;drLegal 에서 참고하실 수 있습니다.

+

다만 위의 내용이 법률적 조언은 아닌 점 참고 바랍니다.

+
+
+
+

Credits

+

이 패키지는 Cookiecutter 와 elbakramer/cookiecutter-poetry 프로젝트 탬플릿을 사용하여 생성되었습니다.

+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 619c3f0d..00000000 --- a/requirements.txt +++ /dev/null @@ -1,60 +0,0 @@ -aiohttp==3.8.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -aiosignal==1.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -async-timeout==4.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -attrs==22.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" -certifi==2022.9.24 ; python_full_version >= "3.8.1" and python_version < "3.11" -cffi==1.15.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -charset-normalizer==2.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -click==8.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -colorama==0.4.5 ; python_full_version >= "3.8.1" and python_version < "3.11" and platform_system == "Windows" -comtypes==1.1.14 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -cryptography==38.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -deprecated==1.2.13 ; python_full_version >= "3.8.1" and python_version < "3.11" -discord-py==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -et-xmlfile==1.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -exchange-calendars==4.2.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -frozenlist==1.3.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -greenlet==1.1.3 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "3.11" -grpcio-tools==1.48.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -grpcio==1.48.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -idna==3.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -korean-lunar-calendar==0.3.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -lxml==4.9.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -multidict==6.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -numpy==1.23.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -openpyxl==3.0.10 ; python_full_version >= "3.8.1" and python_version < "3.11" -packaging==21.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -pandas==1.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -protobuf==3.20.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -psutil==5.9.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -pycparser==2.21 ; python_full_version >= "3.8.1" and python_version < "3.11" -pygtrie==2.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyhocon==0.3.59 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyluach==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyparsing==2.4.7 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyside2==5.15.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -python-dateutil==2.8.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytz==2022.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -pywin32==304 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -pywinauto==0.6.8 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -qtpy==2.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -requests==2.28.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -rx==3.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -schedule==1.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -send2trash==1.8.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -setuptools==65.4.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -shiboken2==5.15.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -sqlalchemy==1.4.41 ; python_full_version >= "3.8.1" and python_version < "3.11" -tabulate==0.9.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -toolz==0.12.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -tqdm==4.64.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -typing-extensions==4.4.0 ; python_full_version >= "3.8.1" and python_version < "3.10" -tzdata==2022.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -tzlocal==4.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -urllib3==1.26.12 ; python_full_version >= "3.8.1" and python_version < "3.11" -windows-curses==2.3.0 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -wrapt==1.14.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -yarl==1.8.1 ; python_full_version >= "3.8.1" and python_version < "3.11" diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 059d7e22..00000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,170 +0,0 @@ -actions-toolkit==0.1.14 ; python_full_version >= "3.8.1" and python_version < "3.11" -aiohttp==3.8.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -aiosignal==1.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -alabaster==0.7.12 ; python_full_version >= "3.8.1" and python_version < "3.11" -appnope==0.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "darwin" -astroid==2.12.10 ; python_full_version >= "3.8.1" and python_version < "3.11" -asttokens==2.0.8 ; python_full_version >= "3.8.1" and python_version < "3.11" -astunparse==1.6.3 ; python_full_version >= "3.8.1" and python_version < "3.9" -async-timeout==4.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -attrs==22.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -babel==2.10.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -backcall==0.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" -beautifulsoup4==4.11.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -black==22.10.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -bleach==5.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -build==0.8.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -bump2version==1.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -certifi==2022.9.24 ; python_full_version >= "3.8.1" and python_version < "3.11" -cffi==1.15.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -cfgv==3.3.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -charset-normalizer==2.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -click==8.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -codecov==2.1.12 ; python_full_version >= "3.8.1" and python_version < "3.11" -colorama==0.4.5 ; python_full_version >= "3.8.1" and python_version < "3.11" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" or python_full_version >= "3.8.1" and python_version < "3.11" and os_name == "nt" -comtypes==1.1.14 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -coverage==6.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -coverage[toml]==6.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -cryptography==38.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -decorator==5.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -defusedxml==0.7.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -deprecated==1.2.13 ; python_full_version >= "3.8.1" and python_version < "3.11" -dill==0.3.5.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -discord-py==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -distlib==0.3.6 ; python_full_version >= "3.8.1" and python_version < "3.11" -docutils==0.19 ; python_full_version >= "3.8.1" and python_version < "3.11" -dunamai==1.13.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -entrypoints==0.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -et-xmlfile==1.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -exchange-calendars==4.2.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -execnet==1.9.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -executing==1.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -fastjsonschema==2.16.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -filelock==3.8.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -flake8==5.0.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -frozenlist==1.3.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -greenlet==1.1.3 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "3.11" -grpcio-tools==1.48.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -grpcio==1.48.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -identify==2.5.6 ; python_full_version >= "3.8.1" and python_version < "3.11" -idna==3.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -imagesize==1.4.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -importlib-metadata==5.0.0 ; python_full_version >= "3.8.1" and python_version < "3.10" -importlib-resources==5.10.0 ; python_full_version >= "3.8.1" and python_version < "3.9" -iniconfig==1.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -ipython==8.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -isort==5.10.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -jedi==0.18.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -jinja2==3.1.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -jsonschema==4.16.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -jupyter-client==7.3.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -jupyter-core==4.11.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -jupyterlab-pygments==0.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -korean-lunar-calendar==0.3.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -lazy-object-proxy==1.7.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -lxml==4.9.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -markupsafe==2.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -matplotlib-inline==0.1.6 ; python_full_version >= "3.8.1" and python_version < "3.11" -mccabe==0.7.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -mistune==2.0.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -multidict==6.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -mypy-extensions==0.4.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -mypy==0.982 ; python_full_version >= "3.8.1" and python_version < "3.11" -nbclient==0.7.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -nbconvert==7.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -nbformat==5.6.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -nbsphinx==0.8.9 ; python_full_version >= "3.8.1" and python_version < "3.11" -nest-asyncio==1.5.6 ; python_full_version >= "3.8.1" and python_version < "3.11" -nodeenv==1.7.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -numpy==1.23.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -openpyxl==3.0.10 ; python_full_version >= "3.8.1" and python_version < "3.11" -packaging==21.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -pandas==1.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pandocfilters==1.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -parso==0.8.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -pathspec==0.10.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pep517==0.13.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pexpect==4.8.0 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform != "win32" -pickleshare==0.7.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -pip-tools==6.9.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pip==22.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -pkgutil-resolve-name==1.3.10 ; python_full_version >= "3.8.1" and python_version < "3.9" -platformdirs==2.5.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -pluggy==1.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pre-commit==2.20.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -prompt-toolkit==3.0.31 ; python_full_version >= "3.8.1" and python_version < "3.11" -protobuf==3.20.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -psutil==5.9.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -ptyprocess==0.7.0 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform != "win32" -pure-eval==0.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -py==1.11.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pycodestyle==2.9.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pycparser==2.21 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyflakes==2.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pygithub==1.55 ; python_full_version >= "3.8.1" and python_version < "3.11" -pygments==2.13.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pygtrie==2.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyhocon==0.3.59 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyjwt==2.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pylint==2.15.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyluach==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pynacl==1.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyparsing==2.4.7 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyrsistent==0.18.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyside2==5.15.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytest-cov==4.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytest-forked==1.4.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytest-xdist==2.5.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytest==7.1.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -python-dateutil==2.8.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pytz==2022.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyupgrade==3.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pywin32==304 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -pywinauto==0.6.8 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -pyyaml==6.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -pyzmq==24.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -qtpy==2.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -requests==2.28.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -rx==3.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -schedule==1.1.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -send2trash==1.8.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -setuptools==65.4.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -shiboken2==5.15.2.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -snowballstemmer==2.2.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -soupsieve==2.3.2.post1 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinx-autoapi==2.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinx==5.2.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-applehelp==1.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-devhelp==1.0.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-htmlhelp==2.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-jsmath==1.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-qthelp==1.0.3 ; python_full_version >= "3.8.1" and python_version < "3.11" -sphinxcontrib-serializinghtml==1.1.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -sqlalchemy==1.4.41 ; python_full_version >= "3.8.1" and python_version < "3.11" -stack-data==0.5.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -tabulate==0.9.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -tinycss2==1.1.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -tokenize-rt==5.0.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -toml==0.10.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -tomli==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -tomlkit==0.11.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -toolz==0.12.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -tornado==6.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -tqdm==4.64.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -traitlets==5.4.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -typing-extensions==4.4.0 ; python_full_version >= "3.8.1" and python_version < "3.11" -tzdata==2022.4 ; python_full_version >= "3.8.1" and python_version < "3.11" -tzlocal==4.2 ; python_full_version >= "3.8.1" and python_version < "3.11" -unidecode==1.3.6 ; python_full_version >= "3.8.1" and python_version < "3.11" -urllib3==1.26.12 ; python_full_version >= "3.8.1" and python_version < "3.11" -virtualenv==20.16.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -wcwidth==0.2.5 ; python_full_version >= "3.8.1" and python_version < "3.11" -webencodings==0.5.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -wheel==0.37.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -windows-curses==2.3.0 ; python_full_version >= "3.8.1" and python_version < "3.11" and sys_platform == "win32" -wrapt==1.14.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -yarl==1.8.1 ; python_full_version >= "3.8.1" and python_version < "3.11" -zipp==3.9.0 ; python_full_version >= "3.8.1" and python_version < "3.10" diff --git a/search.html b/search.html new file mode 100644 index 00000000..e0c7be6a --- /dev/null +++ b/search.html @@ -0,0 +1,164 @@ + + + + + + + + Search — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..e2c0e37e --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["authors","autoapi/index","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index","autoapi/koapy/backend/daishin_cybos_plus/core/index","autoapi/koapy/backend/daishin_cybos_plus/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index","autoapi/koapy/backend/daishin_cybos_plus/proxy/index","autoapi/koapy/backend/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index","autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index","autoapi/koapy/backend/kiwoom_open_api_plus/index","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index","autoapi/koapy/backend/kiwoom_open_api_w/core/index","autoapi/koapy/backend/kiwoom_open_api_w/index","autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index","autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index","autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index","autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index","autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index","autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index","autoapi/koapy/backtrader/KrxTradingCalendar/index","autoapi/koapy/backtrader/SQLAlchemyData/index","autoapi/koapy/backtrader/SQLAlchemySQLiteData/index","autoapi/koapy/backtrader/SQLiteData/index","autoapi/koapy/backtrader/index","autoapi/koapy/cli/__main__/index","autoapi/koapy/cli/commands/disable/auto_login/index","autoapi/koapy/cli/commands/disable/index","autoapi/koapy/cli/commands/enable/auto_login/index","autoapi/koapy/cli/commands/enable/index","autoapi/koapy/cli/commands/generate/grpc/index","autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index","autoapi/koapy/cli/commands/generate/index","autoapi/koapy/cli/commands/generate/openapi/index","autoapi/koapy/cli/commands/generate/openapi/python_stubs/index","autoapi/koapy/cli/commands/get/account_data/deposit/index","autoapi/koapy/cli/commands/get/account_data/evaluation/index","autoapi/koapy/cli/commands/get/account_data/index","autoapi/koapy/cli/commands/get/account_data/orders/index","autoapi/koapy/cli/commands/get/account_data/userinfo/index","autoapi/koapy/cli/commands/get/chart_data/daily/index","autoapi/koapy/cli/commands/get/chart_data/index","autoapi/koapy/cli/commands/get/chart_data/minute/index","autoapi/koapy/cli/commands/get/index","autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index","autoapi/koapy/cli/commands/get/openapi_meta/index","autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index","autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index","autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index","autoapi/koapy/cli/commands/get/stock_meta/codelist/index","autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index","autoapi/koapy/cli/commands/get/stock_meta/index","autoapi/koapy/cli/commands/get/stock_meta/stockcode/index","autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index","autoapi/koapy/cli/commands/get/stock_meta/stockname/index","autoapi/koapy/cli/commands/index","autoapi/koapy/cli/commands/install/index","autoapi/koapy/cli/commands/install/openapi/index","autoapi/koapy/cli/commands/install/pywin32/index","autoapi/koapy/cli/commands/serve/index","autoapi/koapy/cli/commands/show/account_window/index","autoapi/koapy/cli/commands/show/index","autoapi/koapy/cli/commands/uninstall/index","autoapi/koapy/cli/commands/uninstall/openapi/index","autoapi/koapy/cli/commands/uninstall/pywin32/index","autoapi/koapy/cli/commands/update/index","autoapi/koapy/cli/extensions/functools/index","autoapi/koapy/cli/extensions/index","autoapi/koapy/cli/extensions/parser/index","autoapi/koapy/cli/extensions/verbose_option/index","autoapi/koapy/cli/index","autoapi/koapy/cli/utils/credentials/index","autoapi/koapy/cli/utils/fail_with_usage/index","autoapi/koapy/cli/utils/grpc_options/index","autoapi/koapy/cli/utils/index","autoapi/koapy/cli/utils/openapi/index","autoapi/koapy/cli/utils/pywin32/index","autoapi/koapy/cli/utils/verbose_option/index","autoapi/koapy/compat/index","autoapi/koapy/compat/pyside2/QtAxContainer/index","autoapi/koapy/compat/pyside2/QtCore/index","autoapi/koapy/compat/pyside2/QtGui/index","autoapi/koapy/compat/pyside2/QtNetwork/index","autoapi/koapy/compat/pyside2/QtWidgets/index","autoapi/koapy/compat/pyside2/index","autoapi/koapy/compat/pywinauto/findwindows/index","autoapi/koapy/compat/pywinauto/importlib/index","autoapi/koapy/compat/pywinauto/index","autoapi/koapy/compat/pywinauto/timings/index","autoapi/koapy/config/index","autoapi/koapy/index","autoapi/koapy/utils/builtin/index","autoapi/koapy/utils/ctypes/index","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index","autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index","autoapi/koapy/utils/data/index","autoapi/koapy/utils/datetime/index","autoapi/koapy/utils/exchange_calendars/index","autoapi/koapy/utils/grpc/index","autoapi/koapy/utils/index","autoapi/koapy/utils/itertools/index","autoapi/koapy/utils/logging/Logging/index","autoapi/koapy/utils/logging/index","autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index","autoapi/koapy/utils/logging/pyside2/QObjectLogging/index","autoapi/koapy/utils/logging/pyside2/QThreadLogging/index","autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index","autoapi/koapy/utils/logging/pyside2/index","autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index","autoapi/koapy/utils/logging/tqdm/index","autoapi/koapy/utils/messaging/DiscordMessenger/index","autoapi/koapy/utils/messaging/Messenger/index","autoapi/koapy/utils/messaging/index","autoapi/koapy/utils/networking/index","autoapi/koapy/utils/notimplemented/index","autoapi/koapy/utils/platform/index","autoapi/koapy/utils/pywin32/index","autoapi/koapy/utils/rate_limiting/RateLimiter/index","autoapi/koapy/utils/rate_limiting/index","autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index","autoapi/koapy/utils/rate_limiting/pyside2/index","autoapi/koapy/utils/recursion/index","autoapi/koapy/utils/serialization/index","autoapi/koapy/utils/store/SQLiteFileLibrary/index","autoapi/koapy/utils/store/SQLiteStore/index","autoapi/koapy/utils/store/SQLiteStoreLibrary/index","autoapi/koapy/utils/store/index","autoapi/koapy/utils/store/misc/VersionedItem/index","autoapi/koapy/utils/store/misc/index","autoapi/koapy/utils/store/sqlalchemy/Base/index","autoapi/koapy/utils/store/sqlalchemy/Library/index","autoapi/koapy/utils/store/sqlalchemy/Session/index","autoapi/koapy/utils/store/sqlalchemy/Snapshot/index","autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index","autoapi/koapy/utils/store/sqlalchemy/Symbol/index","autoapi/koapy/utils/store/sqlalchemy/Timestamp/index","autoapi/koapy/utils/store/sqlalchemy/Version/index","autoapi/koapy/utils/store/sqlalchemy/index","autoapi/koapy/utils/subprocess/index","autoapi/koapy/utils/threading/index","contributing","history","index","installation","notebooks/getting-historical-stock-price-data","notebooks/index","notebooks/koapy-tutorial","readme","usage"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":5,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.intersphinx":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["authors.rst","autoapi/index.rst","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypoint/index.rst","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusEntrypointMixin/index.rst","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusError/index.rst","autoapi/koapy/backend/daishin_cybos_plus/core/CybosPlusRateLimiter/index.rst","autoapi/koapy/backend/daishin_cybos_plus/core/index.rst","autoapi/koapy/backend/daishin_cybos_plus/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusEntrypointProxy/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceMessageUtils/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyServiceServicer/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/CybosPlusProxyService_pb2_grpc/index.rst","autoapi/koapy/backend/daishin_cybos_plus/proxy/index.rst","autoapi/koapy/backend/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusCondition/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchFunctions/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDispatchSignature/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusDynamicCallable/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypoint/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEntrypointMixin/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusError/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventFunctions/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerFunctions/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusEventHandlerSignature/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusLoggingEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidget/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusQAxWidgetMixin/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRateLimiter/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusRealType/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusScreenManager/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignalConnector/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusSignature/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTrInfo/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLib/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusTypeLibSpec/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/KiwoomOpenApiPlusVersionUpdater/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/generate_python_stubs/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/core/tools/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClient/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideDynamicCallable/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientSideSignalConnector/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceClientStubWrapper/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceMessageUtils/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServer/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusServiceServicer/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService_pb2_grpc/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusConditionEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlerForGrpc/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusEventHandlers/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusKwTrEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoadConditionEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoggingEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusLoginEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusOrderEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusRealEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/KiwoomOpenApiPlusTrEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/event/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/compile_proto/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/grpc/tools/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusDialogHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusManagerApplication/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusServerApplication/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/KiwoomOpenApiPlusSignalHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/pyside2/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/PipeableMultiThreadedRendezvous/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/grpc/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/list_conversion/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/module_path/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QDialogHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QSignalHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/QThreadPoolExecutor/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/pyside2/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedBufferedIterator/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueBasedIterableObserver/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/QueueIterator/index.rst","autoapi/koapy/backend/kiwoom_open_api_plus/utils/queue/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWDynamicCallable/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEntrypoint/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWError/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWEventHandlerFunctions/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWLoggingEventHandler/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidget/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWQAxWidgetMixin/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignalConnector/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/KiwoomOpenApiWSignature/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/core/index.rst","autoapi/koapy/backend/kiwoom_open_api_w/index.rst","autoapi/koapy/backtrader/KiwoomOpenApiPlusBroker/index.rst","autoapi/koapy/backtrader/KiwoomOpenApiPlusData/index.rst","autoapi/koapy/backtrader/KiwoomOpenApiPlusEventStreamer/index.rst","autoapi/koapy/backtrader/KiwoomOpenApiPlusStore/index.rst","autoapi/koapy/backtrader/KrxHistoricalDailyPriceData/index.rst","autoapi/koapy/backtrader/KrxHistoricalDailyPriceDataFromSQLite/index.rst","autoapi/koapy/backtrader/KrxTradingCalendar/index.rst","autoapi/koapy/backtrader/SQLAlchemyData/index.rst","autoapi/koapy/backtrader/SQLAlchemySQLiteData/index.rst","autoapi/koapy/backtrader/SQLiteData/index.rst","autoapi/koapy/backtrader/index.rst","autoapi/koapy/cli/__main__/index.rst","autoapi/koapy/cli/commands/disable/auto_login/index.rst","autoapi/koapy/cli/commands/disable/index.rst","autoapi/koapy/cli/commands/enable/auto_login/index.rst","autoapi/koapy/cli/commands/enable/index.rst","autoapi/koapy/cli/commands/generate/grpc/index.rst","autoapi/koapy/cli/commands/generate/grpc/ssl_credentials/index.rst","autoapi/koapy/cli/commands/generate/index.rst","autoapi/koapy/cli/commands/generate/openapi/index.rst","autoapi/koapy/cli/commands/generate/openapi/python_stubs/index.rst","autoapi/koapy/cli/commands/get/account_data/deposit/index.rst","autoapi/koapy/cli/commands/get/account_data/evaluation/index.rst","autoapi/koapy/cli/commands/get/account_data/index.rst","autoapi/koapy/cli/commands/get/account_data/orders/index.rst","autoapi/koapy/cli/commands/get/account_data/userinfo/index.rst","autoapi/koapy/cli/commands/get/chart_data/daily/index.rst","autoapi/koapy/cli/commands/get/chart_data/index.rst","autoapi/koapy/cli/commands/get/chart_data/minute/index.rst","autoapi/koapy/cli/commands/get/index.rst","autoapi/koapy/cli/commands/get/openapi_meta/errmsg/index.rst","autoapi/koapy/cli/commands/get/openapi_meta/index.rst","autoapi/koapy/cli/commands/get/openapi_meta/modulepath/index.rst","autoapi/koapy/cli/commands/get/openapi_meta/realinfo/index.rst","autoapi/koapy/cli/commands/get/openapi_meta/trinfo/index.rst","autoapi/koapy/cli/commands/get/stock_meta/codelist/index.rst","autoapi/koapy/cli/commands/get/stock_meta/codelist_interactive/index.rst","autoapi/koapy/cli/commands/get/stock_meta/index.rst","autoapi/koapy/cli/commands/get/stock_meta/stockcode/index.rst","autoapi/koapy/cli/commands/get/stock_meta/stockinfo/index.rst","autoapi/koapy/cli/commands/get/stock_meta/stockname/index.rst","autoapi/koapy/cli/commands/index.rst","autoapi/koapy/cli/commands/install/index.rst","autoapi/koapy/cli/commands/install/openapi/index.rst","autoapi/koapy/cli/commands/install/pywin32/index.rst","autoapi/koapy/cli/commands/serve/index.rst","autoapi/koapy/cli/commands/show/account_window/index.rst","autoapi/koapy/cli/commands/show/index.rst","autoapi/koapy/cli/commands/uninstall/index.rst","autoapi/koapy/cli/commands/uninstall/openapi/index.rst","autoapi/koapy/cli/commands/uninstall/pywin32/index.rst","autoapi/koapy/cli/commands/update/index.rst","autoapi/koapy/cli/extensions/functools/index.rst","autoapi/koapy/cli/extensions/index.rst","autoapi/koapy/cli/extensions/parser/index.rst","autoapi/koapy/cli/extensions/verbose_option/index.rst","autoapi/koapy/cli/index.rst","autoapi/koapy/cli/utils/credentials/index.rst","autoapi/koapy/cli/utils/fail_with_usage/index.rst","autoapi/koapy/cli/utils/grpc_options/index.rst","autoapi/koapy/cli/utils/index.rst","autoapi/koapy/cli/utils/openapi/index.rst","autoapi/koapy/cli/utils/pywin32/index.rst","autoapi/koapy/cli/utils/verbose_option/index.rst","autoapi/koapy/compat/index.rst","autoapi/koapy/compat/pyside2/QtAxContainer/index.rst","autoapi/koapy/compat/pyside2/QtCore/index.rst","autoapi/koapy/compat/pyside2/QtGui/index.rst","autoapi/koapy/compat/pyside2/QtNetwork/index.rst","autoapi/koapy/compat/pyside2/QtWidgets/index.rst","autoapi/koapy/compat/pyside2/index.rst","autoapi/koapy/compat/pywinauto/findwindows/index.rst","autoapi/koapy/compat/pywinauto/importlib/index.rst","autoapi/koapy/compat/pywinauto/index.rst","autoapi/koapy/compat/pywinauto/timings/index.rst","autoapi/koapy/config/index.rst","autoapi/koapy/index.rst","autoapi/koapy/utils/builtin/index.rst","autoapi/koapy/utils/ctypes/index.rst","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataDownloader/index.rst","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataForBacktestLoader/index.rst","autoapi/koapy/utils/data/KrxHistoricalDailyPriceDataLoader/index.rst","autoapi/koapy/utils/data/YahooFinanceKrxHistoricalDailyPriceDataDownloader/index.rst","autoapi/koapy/utils/data/index.rst","autoapi/koapy/utils/datetime/index.rst","autoapi/koapy/utils/exchange_calendars/index.rst","autoapi/koapy/utils/grpc/index.rst","autoapi/koapy/utils/index.rst","autoapi/koapy/utils/itertools/index.rst","autoapi/koapy/utils/logging/Logging/index.rst","autoapi/koapy/utils/logging/index.rst","autoapi/koapy/utils/logging/pyside2/QAbstractSocketLogging/index.rst","autoapi/koapy/utils/logging/pyside2/QObjectLogging/index.rst","autoapi/koapy/utils/logging/pyside2/QThreadLogging/index.rst","autoapi/koapy/utils/logging/pyside2/QWidgetLogging/index.rst","autoapi/koapy/utils/logging/pyside2/index.rst","autoapi/koapy/utils/logging/tqdm/TqdmStreamHandler/index.rst","autoapi/koapy/utils/logging/tqdm/index.rst","autoapi/koapy/utils/messaging/DiscordMessenger/index.rst","autoapi/koapy/utils/messaging/Messenger/index.rst","autoapi/koapy/utils/messaging/index.rst","autoapi/koapy/utils/networking/index.rst","autoapi/koapy/utils/notimplemented/index.rst","autoapi/koapy/utils/platform/index.rst","autoapi/koapy/utils/pywin32/index.rst","autoapi/koapy/utils/rate_limiting/RateLimiter/index.rst","autoapi/koapy/utils/rate_limiting/index.rst","autoapi/koapy/utils/rate_limiting/pyside2/QRateLimitedExecutor/index.rst","autoapi/koapy/utils/rate_limiting/pyside2/index.rst","autoapi/koapy/utils/recursion/index.rst","autoapi/koapy/utils/serialization/index.rst","autoapi/koapy/utils/store/SQLiteFileLibrary/index.rst","autoapi/koapy/utils/store/SQLiteStore/index.rst","autoapi/koapy/utils/store/SQLiteStoreLibrary/index.rst","autoapi/koapy/utils/store/index.rst","autoapi/koapy/utils/store/misc/VersionedItem/index.rst","autoapi/koapy/utils/store/misc/index.rst","autoapi/koapy/utils/store/sqlalchemy/Base/index.rst","autoapi/koapy/utils/store/sqlalchemy/Library/index.rst","autoapi/koapy/utils/store/sqlalchemy/Session/index.rst","autoapi/koapy/utils/store/sqlalchemy/Snapshot/index.rst","autoapi/koapy/utils/store/sqlalchemy/SnapshotAssociation/index.rst","autoapi/koapy/utils/store/sqlalchemy/Symbol/index.rst","autoapi/koapy/utils/store/sqlalchemy/Timestamp/index.rst","autoapi/koapy/utils/store/sqlalchemy/Version/index.rst","autoapi/koapy/utils/store/sqlalchemy/index.rst","autoapi/koapy/utils/subprocess/index.rst","autoapi/koapy/utils/threading/index.rst","contributing.rst","history.rst","index.rst","installation.rst","notebooks/getting-historical-stock-price-data.rst","notebooks/index.rst","notebooks/koapy-tutorial.rst","readme.rst","usage.rst"],objects:{"":[[172,0,0,"-","koapy"]],"koapy.backend":[[7,0,0,"-","daishin_cybos_plus"],[65,0,0,"-","kiwoom_open_api_plus"],[95,0,0,"-","kiwoom_open_api_w"]],"koapy.backend.daishin_cybos_plus":[[6,0,0,"-","core"],[14,0,0,"-","proxy"]],"koapy.backend.daishin_cybos_plus.core":[[2,0,0,"-","CybosPlusEntrypoint"],[3,0,0,"-","CybosPlusEntrypointMixin"],[4,0,0,"-","CybosPlusError"],[5,0,0,"-","CybosPlusRateLimiter"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint":[[2,1,1,"","CybosPlusDispatch"],[2,1,1,"","CybosPlusEntrypoint"],[2,1,1,"","CybosPlusIncompleteProgID"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin":[[3,1,1,"","CybosPlusEntrypointMixin"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin.CybosPlusEntrypointMixin":[[3,2,1,"","CommConnect"],[3,2,1,"","Connect"],[3,2,1,"","ConnectUsingPywinauto"],[3,2,1,"","ConnectUsingPywinauto_Impl"],[3,2,1,"","ConnectUsingPywinauto_RunScriptInSubprocess"],[3,2,1,"","EnsureConnected"],[3,2,1,"","GetCodeListByMarketAsList"],[3,2,1,"","GetConnectState"],[3,2,1,"","GetCurrentStockDataAsDataFrame"],[3,2,1,"","GetDailyAdjustmentRatioAsDataFrame"],[3,2,1,"","GetDailyStockDataAsDataFrame"],[3,2,1,"","GetGeneralCodeList"],[3,2,1,"","GetKosdaqCodeList"],[3,2,1,"","GetKospiCodeList"],[3,2,1,"","GetMinuteStockDataAsDataFrame"],[3,2,1,"","GetStockDataAsDataFrame"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusError":[[4,3,1,"","CybosPlusError"],[4,3,1,"","CybosPlusRequestError"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusError.CybosPlusRequestError":[[4,4,1,"","ERROR_MESSAGE_BY_CODE"],[4,2,1,"","check_code_or_raise"],[4,2,1,"","code"],[4,2,1,"","get_error_message_by_code"],[4,2,1,"","message"],[4,2,1,"","try_or_raise"],[4,2,1,"","wrap_to_check_code_or_raise"]],"koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter":[[5,1,1,"","CybosPlusLookupRequestRateLimiter"],[5,1,1,"","CybosPlusTradeRequestRateLimiter"]],"koapy.backend.daishin_cybos_plus.proxy":[[8,0,0,"-","CybosPlusEntrypointProxy"],[9,0,0,"-","CybosPlusProxyService"],[10,0,0,"-","CybosPlusProxyServiceMessageUtils"],[11,0,0,"-","CybosPlusProxyServiceServicer"],[12,0,0,"-","CybosPlusProxyService_pb2"],[13,0,0,"-","CybosPlusProxyService_pb2_grpc"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy":[[8,1,1,"","CybosPlusDispatchProxy"],[8,1,1,"","CybosPlusDispatchProxyMethod"],[8,1,1,"","CybosPlusEntrypointProxy"],[8,1,1,"","CybosPlusIncompleteProgIDProxy"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService":[[9,1,1,"","CybosPlusProxyService"],[9,5,1,"","main"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils":[[10,5,1,"","AssignPrimitive"],[10,5,1,"","ExtractPrimitive"],[10,5,1,"","Protoc"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer":[[11,1,1,"","CybosPlusEvent"],[11,1,1,"","CybosPlusEventHandler"],[11,1,1,"","CybosPlusEventIterator"],[11,1,1,"","CybosPlusProxyServiceServicer"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEvent":[[11,2,1,"","done"],[11,2,1,"","wait_for_done"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventHandler":[[11,2,1,"","OnRecieved"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusEventIterator":[[11,2,1,"","notify"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer.CybosPlusProxyServiceServicer":[[11,2,1,"","Dispatch"],[11,2,1,"","Event"],[11,2,1,"","Method"],[11,2,1,"","Property"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2":[[12,6,1,"","Argument"],[12,6,1,"","DESCRIPTOR"],[12,6,1,"","DispatchRequest"],[12,6,1,"","DispatchResponse"],[12,6,1,"","EventDoneRequest"],[12,6,1,"","EventFiredResponse"],[12,6,1,"","EventRequest"],[12,6,1,"","EventResponse"],[12,6,1,"","EventStartRequest"],[12,6,1,"","EventStartedResponse"],[12,6,1,"","EventStopRequest"],[12,6,1,"","MethodRequest"],[12,6,1,"","MethodResponse"],[12,6,1,"","PrimitiveValue"],[12,6,1,"","PrimitiveValueArray"],[12,6,1,"","PropertyRequest"],[12,6,1,"","PropertyResponse"],[12,6,1,"id18","containing_oneof"],[12,6,1,"id16","message_type"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc":[[13,1,1,"","CybosPlusProxyService"],[13,1,1,"","CybosPlusProxyServiceServicer"],[13,1,1,"","CybosPlusProxyServiceStub"],[13,5,1,"","add_CybosPlusProxyServiceServicer_to_server"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyService":[[13,2,1,"","Dispatch"],[13,2,1,"","Event"],[13,2,1,"","Method"],[13,2,1,"","Property"]],"koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc.CybosPlusProxyServiceServicer":[[13,2,1,"","Dispatch"],[13,2,1,"","Event"],[13,2,1,"","Method"],[13,2,1,"","Property"]],"koapy.backend.kiwoom_open_api_plus":[[39,0,0,"-","core"],[62,0,0,"-","grpc"],[70,0,0,"-","pyside2"],[73,0,0,"-","utils"]],"koapy.backend.kiwoom_open_api_plus.core":[[16,0,0,"-","KiwoomOpenApiPlusCondition"],[17,0,0,"-","KiwoomOpenApiPlusDispatchFunctions"],[18,0,0,"-","KiwoomOpenApiPlusDispatchSignature"],[19,0,0,"-","KiwoomOpenApiPlusDynamicCallable"],[20,0,0,"-","KiwoomOpenApiPlusEntrypoint"],[21,0,0,"-","KiwoomOpenApiPlusEntrypointMixin"],[22,0,0,"-","KiwoomOpenApiPlusError"],[23,0,0,"-","KiwoomOpenApiPlusEventFunctions"],[24,0,0,"-","KiwoomOpenApiPlusEventHandler"],[25,0,0,"-","KiwoomOpenApiPlusEventHandlerFunctions"],[26,0,0,"-","KiwoomOpenApiPlusEventHandlerSignature"],[27,0,0,"-","KiwoomOpenApiPlusLoggingEventHandler"],[28,0,0,"-","KiwoomOpenApiPlusQAxWidget"],[29,0,0,"-","KiwoomOpenApiPlusQAxWidgetMixin"],[30,0,0,"-","KiwoomOpenApiPlusRateLimiter"],[31,0,0,"-","KiwoomOpenApiPlusRealType"],[32,0,0,"-","KiwoomOpenApiPlusScreenManager"],[33,0,0,"-","KiwoomOpenApiPlusSignalConnector"],[34,0,0,"-","KiwoomOpenApiPlusSignature"],[35,0,0,"-","KiwoomOpenApiPlusTrInfo"],[36,0,0,"-","KiwoomOpenApiPlusTypeLib"],[37,0,0,"-","KiwoomOpenApiPlusTypeLibSpec"],[38,0,0,"-","KiwoomOpenApiPlusVersionUpdater"],[41,0,0,"-","tools"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition":[[16,1,1,"","KiwoomOpenApiPlusConditionEntry"],[16,1,1,"","KiwoomOpenApiPlusConditionFile"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionEntry":[[16,2,1,"","from_datfile"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition.KiwoomOpenApiPlusConditionFile":[[16,2,1,"","from_datfile"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions":[[17,1,1,"","KiwoomOpenApiPlusDispatchFunctions"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions.KiwoomOpenApiPlusDispatchFunctions":[[17,2,1,"","CommConnect"],[17,2,1,"","CommGetData"],[17,2,1,"","CommInvestRqData"],[17,2,1,"","CommKwRqData"],[17,2,1,"","CommRqData"],[17,2,1,"","CommTerminate"],[17,2,1,"","DisconnectRealData"],[17,2,1,"","GetAPIModulePath"],[17,2,1,"","GetActPriceList"],[17,2,1,"","GetBranchCodeName"],[17,2,1,"","GetChejanData"],[17,2,1,"","GetCodeListByMarket"],[17,2,1,"","GetCommData"],[17,2,1,"","GetCommDataEx"],[17,2,1,"","GetCommRealData"],[17,2,1,"","GetConditionLoad"],[17,2,1,"","GetConditionNameList"],[17,2,1,"","GetConnectState"],[17,2,1,"","GetDataCount"],[17,2,1,"","GetFutureCodeByIndex"],[17,2,1,"","GetFutureList"],[17,2,1,"","GetLoginInfo"],[17,2,1,"","GetMarketType"],[17,2,1,"","GetMasterCodeName"],[17,2,1,"","GetMasterConstruction"],[17,2,1,"","GetMasterLastPrice"],[17,2,1,"","GetMasterListedStockCnt"],[17,2,1,"","GetMasterListedStockDate"],[17,2,1,"","GetMasterStockState"],[17,2,1,"","GetMonthList"],[17,2,1,"","GetOptionATM"],[17,2,1,"","GetOptionCode"],[17,2,1,"","GetOptionCodeByActPrice"],[17,2,1,"","GetOptionCodeByMonth"],[17,2,1,"","GetOutputValue"],[17,2,1,"","GetRepeatCnt"],[17,2,1,"","GetSActPriceList"],[17,2,1,"","GetSFOBasisAssetList"],[17,2,1,"","GetSFutureCodeByIndex"],[17,2,1,"","GetSFutureList"],[17,2,1,"","GetSMonthList"],[17,2,1,"","GetSOptionATM"],[17,2,1,"","GetSOptionCode"],[17,2,1,"","GetSOptionCodeByActPrice"],[17,2,1,"","GetSOptionCodeByMonth"],[17,2,1,"","GetThemeGroupCode"],[17,2,1,"","GetThemeGroupList"],[17,2,1,"","KOA_Functions"],[17,2,1,"","SendCondition"],[17,2,1,"","SendConditionStop"],[17,2,1,"","SendOrder"],[17,2,1,"","SendOrderCredit"],[17,2,1,"","SendOrderFO"],[17,2,1,"","SetInfoData"],[17,2,1,"","SetInputValue"],[17,2,1,"","SetOutputFID"],[17,2,1,"","SetRealReg"],[17,2,1,"","SetRealRemove"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature":[[18,1,1,"","KiwoomOpenApiPlusDispatchSignature"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature.KiwoomOpenApiPlusDispatchSignature":[[18,4,1,"","DISPATCH_SIGNATURES_BY_NAME"],[18,2,1,"","from_name"],[18,2,1,"","names"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable":[[19,1,1,"","KiwoomOpenApiPlusDynamicCallable"],[19,1,1,"","KiwoomOpenApiPlusDynamicCallableRunnable"],[19,6,1,"","P"],[19,6,1,"","R"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallable":[[19,2,1,"","async_call"],[19,2,1,"","bind_dynamic_call_args"],[19,2,1,"","call"],[19,2,1,"","check_return_value"],[19,2,1,"","dynamic_call"],[19,2,1,"","dynamic_call_and_check"],[19,2,1,"","is_valid_return_type"],[19,2,1,"","on_ready_runnable"],[19,4,1,"","ready_runnable"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable.KiwoomOpenApiPlusDynamicCallableRunnable":[[19,2,1,"","cancel"],[19,2,1,"","run"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint":[[20,1,1,"","KiwoomOpenApiPlusEntrypoint"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint.KiwoomOpenApiPlusEntrypoint":[[20,2,1,"","close"],[20,2,1,"","close_client"],[20,2,1,"","close_server_proc"],[20,2,1,"","get_stub"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin":[[21,1,1,"","KiwoomOpenApiPlusEntrypointMixin"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError":[[22,6,1,"","BoolCompatible"],[22,6,1,"","CallableReturnsInt"],[22,6,1,"","CallableReturnsIntOrBool"],[22,6,1,"","IntCompatible"],[22,6,1,"","IntOrBool"],[22,3,1,"","KiwoomOpenApiPlusBooleanReturnCodeError"],[22,3,1,"","KiwoomOpenApiPlusError"],[22,3,1,"","KiwoomOpenApiPlusNegativeReturnCodeError"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusBooleanReturnCodeError":[[22,4,1,"","OP_ERR_FAILURE"],[22,4,1,"","OP_ERR_SUCCESS"],[22,2,1,"","check_code_or_raise"],[22,2,1,"","code"],[22,2,1,"","try_or_raise"],[22,2,1,"","wrap_to_check_code_or_raise"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusError":[[22,2,1,"","get_error_message_by_code"],[22,2,1,"","message"],[22,2,1,"","try_or_raise"],[22,2,1,"","try_or_raise_boolean"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError.KiwoomOpenApiPlusNegativeReturnCodeError":[[22,4,1,"","ERROR_MESSAGE_BY_CODE"],[22,4,1,"","MSG_ERR_COND_MISMATCH"],[22,4,1,"","MSG_ERR_COND_NOTFOUND"],[22,4,1,"","MSG_ERR_COND_OVERFLOW"],[22,4,1,"","MSG_ERR_CONNECT"],[22,4,1,"","MSG_ERR_DATA_RCV_FAIL"],[22,4,1,"","MSG_ERR_FAIL"],[22,4,1,"","MSG_ERR_FIREWALL"],[22,4,1,"","MSG_ERR_INPUT"],[22,4,1,"","MSG_ERR_LOGIN"],[22,4,1,"","MSG_ERR_MEMORY"],[22,4,1,"","MSG_ERR_MIS_1PER_EXC"],[22,4,1,"","MSG_ERR_MIS_2BILL_EXC"],[22,4,1,"","MSG_ERR_MIS_300CNT_EXC"],[22,4,1,"","MSG_ERR_MIS_3PER_EXC"],[22,4,1,"","MSG_ERR_MIS_500CNT_EXC"],[22,4,1,"","MSG_ERR_MIS_5BILL_EXC"],[22,4,1,"","MSG_ERR_NONE"],[22,4,1,"","MSG_ERR_NO_DATA"],[22,4,1,"","MSG_ERR_ORD_OVERFLOW"],[22,4,1,"","MSG_ERR_ORD_OVERFLOW2"],[22,4,1,"","MSG_ERR_ORD_SYMCODE_EMPTY"],[22,4,1,"","MSG_ERR_ORD_WRONG_ACCTINFO"],[22,4,1,"","MSG_ERR_ORD_WRONG_ACCTNO"],[22,4,1,"","MSG_ERR_ORD_WRONG_INPUT"],[22,4,1,"","MSG_ERR_OTHER_ACC_USE"],[22,4,1,"","MSG_ERR_OVER_MAX_DATA"],[22,4,1,"","MSG_ERR_OVER_MAX_FID"],[22,4,1,"","MSG_ERR_REAL_CANCEL"],[22,4,1,"","MSG_ERR_RQ_STRING_FAIL"],[22,4,1,"","MSG_ERR_RQ_STRUCT_FAIL"],[22,4,1,"","MSG_ERR_SEND_FAIL"],[22,4,1,"","MSG_ERR_SISE_OVERFLOW"],[22,4,1,"","MSG_ERR_SOCKET_CLOSED"],[22,4,1,"","MSG_ERR_TR_FAIL"],[22,4,1,"","MSG_ERR_VERSION"],[22,4,1,"","OP_ERR_COND_MISMATCH"],[22,4,1,"","OP_ERR_COND_NOTFOUND"],[22,4,1,"","OP_ERR_COND_OVERFLOW"],[22,4,1,"","OP_ERR_CONNECT"],[22,4,1,"","OP_ERR_DATA_RCV_FAIL"],[22,4,1,"","OP_ERR_FAIL"],[22,4,1,"","OP_ERR_FIREWALL"],[22,4,1,"","OP_ERR_INPUT"],[22,4,1,"","OP_ERR_LOGIN"],[22,4,1,"","OP_ERR_MEMORY"],[22,4,1,"","OP_ERR_MIS_1PER_EXC"],[22,4,1,"","OP_ERR_MIS_2BILL_EXC"],[22,4,1,"","OP_ERR_MIS_300CNT_EXC"],[22,4,1,"","OP_ERR_MIS_3PER_EXC"],[22,4,1,"","OP_ERR_MIS_500CNT_EXC"],[22,4,1,"","OP_ERR_MIS_5BILL_EXC"],[22,4,1,"","OP_ERR_NONE"],[22,4,1,"","OP_ERR_NO_DATA"],[22,4,1,"","OP_ERR_ORD_OVERFLOW"],[22,4,1,"","OP_ERR_ORD_OVERFLOW2"],[22,4,1,"","OP_ERR_ORD_SYMCODE_EMPTY"],[22,4,1,"","OP_ERR_ORD_WRONG_ACCTINFO"],[22,4,1,"","OP_ERR_ORD_WRONG_ACCTNO"],[22,4,1,"","OP_ERR_ORD_WRONG_INPUT"],[22,4,1,"","OP_ERR_OTHER_ACC_USE"],[22,4,1,"","OP_ERR_OVER_MAX_DATA"],[22,4,1,"","OP_ERR_OVER_MAX_FID"],[22,4,1,"","OP_ERR_REAL_CANCEL"],[22,4,1,"","OP_ERR_RQ_STRING_FAIL"],[22,4,1,"","OP_ERR_RQ_STRUCT_FAIL"],[22,4,1,"","OP_ERR_SEND_FAIL"],[22,4,1,"","OP_ERR_SISE_OVERFLOW"],[22,4,1,"","OP_ERR_SOCKET_CLOSED"],[22,4,1,"","OP_ERR_TR_FAIL"],[22,4,1,"","OP_ERR_VERSION"],[22,2,1,"","check_code_or_raise"],[22,2,1,"","code"],[22,2,1,"","get_error_message_by_code"],[22,2,1,"","try_or_raise"],[22,2,1,"","wrap_to_check_code_or_raise"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions":[[23,1,1,"","KiwoomOpenApiPlusEventFunctions"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions.KiwoomOpenApiPlusEventFunctions":[[23,2,1,"","OnEventConnect"],[23,2,1,"","OnReceiveChejanData"],[23,2,1,"","OnReceiveConditionVer"],[23,2,1,"","OnReceiveInvestRealData"],[23,2,1,"","OnReceiveMsg"],[23,2,1,"","OnReceiveRealCondition"],[23,2,1,"","OnReceiveRealData"],[23,2,1,"","OnReceiveTrCondition"],[23,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler":[[24,1,1,"","KiwoomOpenApiPlusEventHandler"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler.KiwoomOpenApiPlusEventHandler":[[24,2,1,"","add_callback"],[24,2,1,"","close"],[24,2,1,"","connect"],[24,2,1,"","control"],[24,2,1,"","disconnect"],[24,2,1,"","enter"],[24,2,1,"","exit"],[24,2,1,"","names"],[24,2,1,"","observer"],[24,2,1,"","on_enter"],[24,2,1,"","on_exit"],[24,2,1,"","slots"],[24,2,1,"","stop"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions":[[25,1,1,"","KiwoomOpenApiPlusEventHandlerFunctions"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions.KiwoomOpenApiPlusEventHandlerFunctions":[[25,2,1,"","OnEventConnect"],[25,2,1,"","OnReceiveChejanData"],[25,2,1,"","OnReceiveConditionVer"],[25,2,1,"","OnReceiveMsg"],[25,2,1,"","OnReceiveRealCondition"],[25,2,1,"","OnReceiveRealData"],[25,2,1,"","OnReceiveTrCondition"],[25,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature":[[26,1,1,"","KiwoomOpenApiPlusEventHandlerSignature"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature.KiwoomOpenApiPlusEventHandlerSignature":[[26,4,1,"","EVENT_HANDLER_SIGNATURES_BY_NAME"],[26,2,1,"","from_name"],[26,2,1,"","names"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler":[[27,1,1,"","KiwoomOpenApiPlusLoggingEventHandler"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler":[[27,2,1,"","OnEventConnect"],[27,2,1,"","OnReceiveChejanData"],[27,2,1,"","OnReceiveConditionVer"],[27,2,1,"","OnReceiveMsg"],[27,2,1,"","OnReceiveRealCondition"],[27,2,1,"","OnReceiveRealData"],[27,2,1,"","OnReceiveTrCondition"],[27,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget":[[28,1,1,"","KiwoomOpenApiPlusQAxWidget"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget.KiwoomOpenApiPlusQAxWidget":[[28,4,1,"","CLSID"],[28,4,1,"","EVENT_NAMES"],[28,4,1,"","METHOD_NAMES"],[28,4,1,"","PROGID"],[28,2,1,"","changeEvent"],[28,2,1,"","closeEvent"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin":[[29,1,1,"","KiwoomOpenApiPlusQAxWidgetMixin"],[29,1,1,"","KiwoomOpenApiPlusQAxWidgetServerSideMixin"],[29,1,1,"","KiwoomOpenApiPlusQAxWidgetUniversalMixin"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetServerSideMixin":[[29,2,1,"","AtomicCommRqData"],[29,2,1,"","CommRqDataWithInputs"],[29,2,1,"","EnsureConditionLoaded"],[29,2,1,"","IsConditionLoaded"],[29,2,1,"","LoadCondition"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin.KiwoomOpenApiPlusQAxWidgetUniversalMixin":[[29,2,1,"","AddPriceToConditionSearchResult"],[29,2,1,"","CommConnectAndThen"],[29,2,1,"","Connect"],[29,2,1,"","DelPriceFromConditionSearchResult"],[29,2,1,"","DisableAutoLogin"],[29,2,1,"","EnableAutoLogin"],[29,2,1,"","EnableAutoLoginUsingPywinauto"],[29,2,1,"","EnableAutoLoginUsingPywinauto_Impl"],[29,2,1,"","EnableAutoLoginUsingPywinauto_RunScriptInSubprocess"],[29,2,1,"","EnsureAutoLoginEnabled"],[29,2,1,"","EnsureConnected"],[29,2,1,"","EnsureConnectedAndThen"],[29,2,1,"","GetAccountCount"],[29,2,1,"","GetAccountList"],[29,2,1,"","GetAutoLoginDatPath"],[29,2,1,"","GetCodeListByMarketAsList"],[29,2,1,"","GetConditionFilePath"],[29,2,1,"","GetConditionNameListAsList"],[29,2,1,"","GetFirewallStatus"],[29,2,1,"","GetFirstAvailableAccount"],[29,2,1,"","GetGeneralCodeList"],[29,2,1,"","GetKeyboardSecurityStatus"],[29,2,1,"","GetKosdaqCodeList"],[29,2,1,"","GetKospiCodeList"],[29,2,1,"","GetMasterListedStockCntEx"],[29,2,1,"","GetMasterListedStockCntExAsInt"],[29,2,1,"","GetMasterStockInfo"],[29,2,1,"","GetMasterStockInfoAsDict"],[29,2,1,"","GetMasterStockStateAsList"],[29,2,1,"","GetNameListByMarketAsList"],[29,2,1,"","GetServerGubun"],[29,2,1,"","GetStockStates"],[29,2,1,"","GetSurveillanceFlag"],[29,2,1,"","GetUpjongCode"],[29,2,1,"","GetUpjongCodeAsList"],[29,2,1,"","GetUpjongNameByCode"],[29,2,1,"","GetUserId"],[29,2,1,"","GetUserName"],[29,2,1,"","HandleVersionUpgradeUsingPywinauto"],[29,2,1,"","HandleVersionUpgradeUsingPywinauto_Impl"],[29,2,1,"","HandleVersionUpgradeUsingPywinauto_RunScriptInSubprocess"],[29,2,1,"","IsAutoLoginEnabled"],[29,2,1,"","IsConnected"],[29,2,1,"","IsFirewallEnabled"],[29,2,1,"","IsFlaggedForCaution"],[29,2,1,"","IsKeyboardSecurityEnabled"],[29,2,1,"","IsNormal"],[29,2,1,"","IsNotNormal"],[29,2,1,"","IsOrderWarningETF"],[29,2,1,"","IsOrderWarningETFAsBoolean"],[29,2,1,"","IsOrderWarningStock"],[29,2,1,"","IsOrderWarningStockAsBoolean"],[29,2,1,"","IsRealServer"],[29,2,1,"","IsSimulationServer"],[29,2,1,"","IsSuspended"],[29,2,1,"","IsUnderAdministration"],[29,2,1,"","IsUnderSurveillance"],[29,2,1,"","LoginUsingPywinauto"],[29,2,1,"","LoginUsingPywinauto_Impl"],[29,2,1,"","LoginUsingPywinauto_RunScriptInSubprocess"],[29,2,1,"","RunScriptInSubprocess_WithData"],[29,2,1,"","SetConditionSearchFlag"],[29,2,1,"","ShowAccountWindow"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter":[[30,1,1,"","KiwoomOpenApiPlusCommRqDataRateLimiter"],[30,1,1,"","KiwoomOpenApiPlusSendConditionRateLimiter"],[30,1,1,"","KiwoomOpenApiPlusSendOrderRateLimiter"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter.KiwoomOpenApiPlusSendConditionRateLimiter":[[30,2,1,"","add_call_history"],[30,2,1,"","check_sleep_seconds"],[30,2,1,"","get_limiter_per_condition"],[30,2,1,"","sleep_if_necessary"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType":[[31,1,1,"","KiwoomOpenApiPlusRealType"],[31,5,1,"","main"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.KiwoomOpenApiPlusRealType":[[31,1,1,"","Fid"],[31,4,1,"","REALTYPE_BY_DESC"],[31,4,1,"","REALTYPE_BY_DESC_DUMP_FILEDIR"],[31,4,1,"","REALTYPE_BY_DESC_DUMP_FILENAME"],[31,4,1,"","REALTYPE_BY_DESC_DUMP_FILEPATH"],[31,2,1,"","dump_realtype_by_desc"],[31,2,1,"","from_name"],[31,2,1,"","get_fids_by_realtype_name"],[31,2,1,"","get_fids_by_realtype_name_as_string"],[31,2,1,"","get_field_names_by_realtype_name"],[31,2,1,"","get_realtype_info_by_desc"],[31,2,1,"","get_realtype_info_by_name"],[31,2,1,"","get_realtype_info_by_realtype_name"],[31,2,1,"","get_realtype_info_list"],[31,2,1,"","get_realtype_name_list"],[31,2,1,"","load"],[31,2,1,"","load_from_datfile"],[31,2,1,"","load_from_dump_file"],[31,2,1,"","realtype_by_desc_from_datfile"],[31,2,1,"","realtype_by_desc_from_dump_file"],[31,2,1,"","realtypes_from_datfile"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType.KiwoomOpenApiPlusRealType.Fid":[[31,4,1,"","FID_BY_FID"],[31,4,1,"","FID_BY_NAME"],[31,4,1,"","FID_DUMP_FILEDIR"],[31,4,1,"","FID_DUMP_FILENAME"],[31,4,1,"","FID_DUMP_FILEPATH"],[31,4,1,"","FID_DUMP_PROCESSOR"],[31,2,1,"","fids_from_dump_file"],[31,2,1,"","from_fid"],[31,2,1,"","from_name"],[31,2,1,"","get_name_by_fid"],[31,2,1,"","load_from_dump_file"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager":[[32,1,1,"","KiwoomOpenApiPlusScreenManager"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager.KiwoomOpenApiPlusScreenManager":[[32,4,1,"","MAXIMUM_NUMBER_OF_SCREENS"],[32,2,1,"","borrow_screen"],[32,2,1,"","get_free_screen"],[32,2,1,"","get_multiple_free_screens"],[32,2,1,"","get_single_free_screen"],[32,2,1,"","is_inuse"],[32,2,1,"","number_to_screen_no"],[32,2,1,"","return_screen"],[32,2,1,"","screen_no_to_number"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector":[[33,1,1,"","KiwoomOpenApiPlusSignalConnector"],[33,6,1,"","P"],[33,6,1,"","R"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector.KiwoomOpenApiPlusSignalConnector":[[33,2,1,"","call"],[33,2,1,"","connect"],[33,2,1,"","connect_to"],[33,2,1,"","disconnect"],[33,2,1,"","disconnect_from"],[33,2,1,"","is_valid_slot"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature":[[34,1,1,"","KiwoomOpenApiPlusSignature"],[34,6,1,"","NoneType"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature.KiwoomOpenApiPlusSignature":[[34,4,1,"","COMTYPE_TO_PYTHONTYPE"],[34,4,1,"","PYTHONTYPE_TO_QTTYPE"],[34,2,1,"","name"],[34,2,1,"","to_pyside2_function_prototype"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo":[[35,1,1,"","KiwoomOpenApiPlusTrInfo"],[35,5,1,"","infer_fids_by_tr_outputs"],[35,5,1,"","main"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo.KiwoomOpenApiPlusTrInfo":[[35,1,1,"","Field"],[35,4,1,"","SINGLE_TO_MULTI_TRCODES"],[35,4,1,"","TRINFO_BY_CODE"],[35,4,1,"","TRINFO_BY_CODE_DUMP_FILEDIR"],[35,4,1,"","TRINFO_BY_CODE_DUMP_FILENAME"],[35,4,1,"","TRINFO_BY_CODE_DUMP_FILEPATH"],[35,2,1,"","dump_trinfo_by_code"],[35,2,1,"","from_code"],[35,2,1,"","from_dict"],[35,2,1,"","from_encfile"],[35,2,1,"","get_input_names"],[35,2,1,"","get_multi_output_names"],[35,2,1,"","get_single_output_names"],[35,2,1,"","get_trcode_list"],[35,2,1,"","get_trinfo_by_code"],[35,2,1,"","get_trinfo_list"],[35,2,1,"","infos_from_data_dir"],[35,2,1,"","load"],[35,2,1,"","load_from_data_dir"],[35,2,1,"","load_from_dump_file"],[35,2,1,"","swap_output_types"],[35,2,1,"","to_dict"],[35,2,1,"","trinfo_by_code_from_data_dir"],[35,2,1,"","trinfo_by_code_from_dump_file"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib":[[36,6,1,"","DISPATCH_OLE_ITEM"],[36,6,1,"","EVENT_OLE_ITEM"],[36,6,1,"","TYPELIB"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec":[[37,6,1,"","API_MODULE_PATH"],[37,6,1,"","API_MODULE_PATH_FROM_DEFAULT_INSTALLATION"],[37,6,1,"","API_MODULE_PATH_FROM_TYPELIB_DLL"],[37,6,1,"","CONTROL_CLSID"],[37,6,1,"","CONTROL_PROGID"],[37,6,1,"","DISPATCH_CLSID"],[37,6,1,"","EVENT_CLSID"],[37,6,1,"","MODULE_CLSID"],[37,6,1,"","TYPELIB_DLL_PATH"],[37,6,1,"","TYPELIB_SPEC"],[37,6,1,"","TYPELIB_SPECS"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater":[[38,1,1,"","KiwoomOpenApiPlusVersionUpdater"]],"koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater.KiwoomOpenApiPlusVersionUpdater":[[38,2,1,"","check_apply_simulation_window"],[38,2,1,"","disable_autologin"],[38,2,1,"","enable_autologin"],[38,2,1,"","enable_autologin_using_pywinauto"],[38,2,1,"","get_api_module_path"],[38,2,1,"","get_autologin_dat"],[38,2,1,"","handle_version_upgrade_using_pywinauto"],[38,2,1,"","is_autologin_enabled"],[38,2,1,"","login_using_pywinauto"],[38,2,1,"","open_login_window"],[38,2,1,"","open_login_window_impl"],[38,2,1,"","show_account_window"],[38,2,1,"","show_account_window_impl"],[38,2,1,"","try_version_update_using_pywinauto"],[38,2,1,"","update_version_if_necessary"]],"koapy.backend.kiwoom_open_api_plus.core.tools":[[40,0,0,"-","generate_python_stubs"]],"koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs":[[40,5,1,"","generate_python_stubs"]],"koapy.backend.kiwoom_open_api_plus.grpc":[[42,0,0,"-","KiwoomOpenApiPlusServiceClient"],[43,0,0,"-","KiwoomOpenApiPlusServiceClientSideDynamicCallable"],[44,0,0,"-","KiwoomOpenApiPlusServiceClientSideSignalConnector"],[45,0,0,"-","KiwoomOpenApiPlusServiceClientStubWrapper"],[46,0,0,"-","KiwoomOpenApiPlusServiceMessageUtils"],[47,0,0,"-","KiwoomOpenApiPlusServiceServer"],[48,0,0,"-","KiwoomOpenApiPlusServiceServicer"],[49,0,0,"-","KiwoomOpenApiPlusService_pb2"],[50,0,0,"-","KiwoomOpenApiPlusService_pb2_grpc"],[61,0,0,"-","event"],[64,0,0,"-","tools"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient":[[42,1,1,"","KiwoomOpenApiPlusServiceClient"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient.KiwoomOpenApiPlusServiceClient":[[42,2,1,"","close"],[42,2,1,"","get_grpc_stub"],[42,2,1,"","get_stub"],[42,2,1,"","is_ready"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable":[[43,1,1,"","KiwoomOpenApiPlusServiceClientSideDynamicCallable"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector":[[44,1,1,"","KiwoomOpenApiPlusServiceClientSideSignalConnector"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector.KiwoomOpenApiPlusServiceClientSideSignalConnector":[[44,2,1,"","connect"],[44,2,1,"","disconnect"],[44,2,1,"","shutdown"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper":[[45,1,1,"","KiwoomOpenApiPlusServiceClientStubCoreWrapper"],[45,1,1,"","KiwoomOpenApiPlusServiceClientStubExtendedWrapper"],[45,1,1,"","KiwoomOpenApiPlusServiceClientStubWrapper"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubCoreWrapper":[[45,2,1,"","Call"],[45,2,1,"","ConditionCall"],[45,4,1,"","EVENT_NAMES"],[45,2,1,"","EnsureConditionLoaded"],[45,2,1,"","IsConditionLoaded"],[45,2,1,"","LoadCondition"],[45,2,1,"","LoadConditionCall"],[45,2,1,"","LoginCall"],[45,4,1,"","METHOD_NAMES"],[45,2,1,"","OrderCall"],[45,2,1,"","RateLimitedCommRqData"],[45,2,1,"","RateLimitedSendCondition"],[45,2,1,"","RealCall"],[45,2,1,"","SetLogLevel"],[45,2,1,"","TransactionCall"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper.KiwoomOpenApiPlusServiceClientStubExtendedWrapper":[[45,2,1,"","GetAccountEvaluationBalanceAsSeriesAndDataFrame"],[45,2,1,"","GetAccountEvaluationStatusAsSeriesAndDataFrame"],[45,2,1,"","GetAccountExecutionBalanceAsSeriesAndDataFrame"],[45,2,1,"","GetAccountRateOfReturnAsDataFrame"],[45,2,1,"","GetCodeListByCondition"],[45,2,1,"","GetCodeListByConditionAsStream"],[45,2,1,"","GetDailyStockDataAsDataFrame"],[45,2,1,"","GetDepositInfo"],[45,2,1,"","GetMarketPriceInfo"],[45,2,1,"","GetMinuteStockDataAsDataFrame"],[45,2,1,"","GetMonthlyStockDataAsDataFrame"],[45,2,1,"","GetOrderLogAsDataFrame1"],[45,2,1,"","GetOrderLogAsDataFrame2"],[45,2,1,"","GetOrderLogAsDataFrame3"],[45,2,1,"","GetRealDataForCodesAsStream"],[45,2,1,"","GetStockBasicInfoAsDict"],[45,2,1,"","GetStockBasicInfoAsSeries"],[45,2,1,"","GetStockQuoteInfoAsDataFrame"],[45,2,1,"","GetStockQuotes"],[45,2,1,"","GetTickStockDataAsDataFrame"],[45,2,1,"","GetWeeklyStockDataAsDataFrame"],[45,2,1,"","GetYearlyStockDataAsDataFrame"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils":[[46,5,1,"","convert_arguments_from_protobuf_to_python"],[46,5,1,"","convert_arguments_from_python_to_protobuf"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer":[[47,1,1,"","KiwoomOpenApiPlusServiceServer"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer.KiwoomOpenApiPlusServiceServer":[[47,2,1,"","get_host"],[47,2,1,"","get_port"],[47,2,1,"","is_running"],[47,2,1,"","reinitialize_server"],[47,2,1,"","start"],[47,2,1,"","stop"],[47,2,1,"","wait_for_termination"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer":[[48,1,1,"","KiwoomOpenApiPlusServiceServicer"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer.KiwoomOpenApiPlusServiceServicer":[[48,2,1,"","BidirectionalListen"],[48,2,1,"","BidirectionalRealCall"],[48,2,1,"","Call"],[48,2,1,"","ConditionCall"],[48,2,1,"","CustomCallAndListen"],[48,2,1,"","CustomListen"],[48,2,1,"","Listen"],[48,2,1,"","LoadConditionCall"],[48,2,1,"","LoginCall"],[48,2,1,"","OrderCall"],[48,2,1,"","OrderListen"],[48,2,1,"","RealCall"],[48,2,1,"","SetLogLevel"],[48,2,1,"","TransactionCall"],[48,2,1,"","control"],[48,2,1,"","screen_manager"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2":[[49,6,1,"","Argument"],[49,6,1,"","BidirectionalListenRequest"],[49,6,1,"","BidirectionalRealInitializeRequest"],[49,6,1,"","BidirectionalRealRegisterRequest"],[49,6,1,"","BidirectionalRealRemoveRequest"],[49,6,1,"","BidirectionalRealRequest"],[49,6,1,"","BidirectionalRealStopRequest"],[49,6,1,"","CallAndListenRequest"],[49,6,1,"","CallAndListenResponse"],[49,6,1,"","CallRequest"],[49,6,1,"","CallResponse"],[49,6,1,"","ConditionRequest"],[49,6,1,"","ConditionRequestFlags"],[49,6,1,"","DESCRIPTOR"],[49,6,1,"","EQUAL_TO"],[49,6,1,"","GREATER_THAN"],[49,6,1,"","GREATER_THAN_OR_EQUAL_TO"],[49,6,1,"","HandledRequest"],[49,6,1,"","LESS_THAN"],[49,6,1,"","LESS_THAN_OR_EQUAL_TO"],[49,6,1,"","ListenRequest"],[49,6,1,"","ListenResponse"],[49,6,1,"","LoadConditionRequest"],[49,6,1,"","LoginCredentials"],[49,6,1,"","LoginRequest"],[49,6,1,"","MultiData"],[49,6,1,"","NOT_EQUAL_TO"],[49,6,1,"","OrderRequest"],[49,6,1,"","OrderSubscriptionTarget"],[49,6,1,"","RealRequest"],[49,6,1,"","RealRequestFlags"],[49,6,1,"","RepeatedString"],[49,6,1,"","ReturnValue"],[49,6,1,"","SetLogLevelRequest"],[49,6,1,"","SetLogLevelResponse"],[49,6,1,"","SingleData"],[49,6,1,"","StopListenRequest"],[49,6,1,"","TransactionRequest"],[49,6,1,"","TransactionStopCondition"],[49,6,1,"","TransactionStopConditionCompartor"],[49,6,1,"id39","containing_oneof"],[49,6,1,"id25","containing_type"],[49,6,1,"","enum_type"],[49,6,1,"id35","message_type"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc":[[50,1,1,"","KiwoomOpenApiPlusService"],[50,1,1,"","KiwoomOpenApiPlusServiceServicer"],[50,1,1,"","KiwoomOpenApiPlusServiceStub"],[50,5,1,"","add_KiwoomOpenApiPlusServiceServicer_to_server"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusService":[[50,2,1,"","BidirectionalListen"],[50,2,1,"","BidirectionalRealCall"],[50,2,1,"","Call"],[50,2,1,"","ConditionCall"],[50,2,1,"","CustomCallAndListen"],[50,2,1,"","CustomListen"],[50,2,1,"","Listen"],[50,2,1,"","LoadConditionCall"],[50,2,1,"","LoginCall"],[50,2,1,"","OrderCall"],[50,2,1,"","OrderListen"],[50,2,1,"","RealCall"],[50,2,1,"","SetLogLevel"],[50,2,1,"","TransactionCall"]],"koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc.KiwoomOpenApiPlusServiceServicer":[[50,2,1,"","BidirectionalListen"],[50,2,1,"","BidirectionalRealCall"],[50,2,1,"","Call"],[50,2,1,"","ConditionCall"],[50,2,1,"","CustomCallAndListen"],[50,2,1,"","CustomListen"],[50,2,1,"","Listen"],[50,2,1,"","LoadConditionCall"],[50,2,1,"","LoginCall"],[50,2,1,"","OrderCall"],[50,2,1,"","OrderListen"],[50,2,1,"","RealCall"],[50,2,1,"","SetLogLevel"],[50,2,1,"","TransactionCall"]],"koapy.backend.kiwoom_open_api_plus.grpc.event":[[51,0,0,"-","KiwoomOpenApiPlusConditionEventHandler"],[52,0,0,"-","KiwoomOpenApiPlusEventHandlerForGrpc"],[53,0,0,"-","KiwoomOpenApiPlusEventHandlers"],[54,0,0,"-","KiwoomOpenApiPlusKwTrEventHandler"],[55,0,0,"-","KiwoomOpenApiPlusLoadConditionEventHandler"],[56,0,0,"-","KiwoomOpenApiPlusLoggingEventHandler"],[57,0,0,"-","KiwoomOpenApiPlusLoginEventHandler"],[58,0,0,"-","KiwoomOpenApiPlusOrderEventHandler"],[59,0,0,"-","KiwoomOpenApiPlusRealEventHandler"],[60,0,0,"-","KiwoomOpenApiPlusTrEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler":[[51,1,1,"","KiwoomOpenApiPlusConditionEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler.KiwoomOpenApiPlusConditionEventHandler":[[51,2,1,"","OnReceiveRealCondition"],[51,2,1,"","OnReceiveTrCondition"],[51,2,1,"","OnReceiveTrData"],[51,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc":[[52,1,1,"","KiwoomOpenApiPlusEventHandlerForGrpc"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc.KiwoomOpenApiPlusEventHandlerForGrpc":[[52,2,1,"","context"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers":[[53,1,1,"","KiwoomOpenApiPlusAllEventHandler"],[53,1,1,"","KiwoomOpenApiPlusEagerAllEventHandler"],[53,1,1,"","KiwoomOpenApiPlusEagerSomeEventHandler"],[53,1,1,"","KiwoomOpenApiPlusLazyAllEventHandler"],[53,1,1,"","KiwoomOpenApiPlusLazySomeEventHandler"],[53,1,1,"","KiwoomOpenApiPlusSomeBidirectionalEventHandler"],[53,1,1,"","KiwoomOpenApiPlusSomeEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerAllEventHandler":[[53,2,1,"","OnEventConnect"],[53,2,1,"","OnReceiveChejanData"],[53,2,1,"","OnReceiveConditionVer"],[53,2,1,"","OnReceiveMsg"],[53,2,1,"","OnReceiveRealCondition"],[53,2,1,"","OnReceiveRealData"],[53,2,1,"","OnReceiveTrCondition"],[53,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusEagerSomeEventHandler":[[53,2,1,"","slots"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazyAllEventHandler":[[53,2,1,"","OnEventConnect"],[53,2,1,"","OnReceiveChejanData"],[53,2,1,"","OnReceiveConditionVer"],[53,2,1,"","OnReceiveMsg"],[53,2,1,"","OnReceiveRealCondition"],[53,2,1,"","OnReceiveRealData"],[53,2,1,"","OnReceiveTrCondition"],[53,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusLazySomeEventHandler":[[53,2,1,"","slots"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers.KiwoomOpenApiPlusSomeBidirectionalEventHandler":[[53,2,1,"","OnEventConnect"],[53,2,1,"","OnReceiveChejanData"],[53,2,1,"","OnReceiveConditionVer"],[53,2,1,"","OnReceiveMsg"],[53,2,1,"","OnReceiveRealCondition"],[53,2,1,"","OnReceiveRealData"],[53,2,1,"","OnReceiveTrCondition"],[53,2,1,"","OnReceiveTrData"],[53,2,1,"","await_handled"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler":[[54,1,1,"","KiwoomOpenApiPlusKwTrEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler.KiwoomOpenApiPlusKwTrEventHandler":[[54,2,1,"","OnEventConnect"],[54,2,1,"","OnReceiveMsg"],[54,2,1,"","OnReceiveTrData"],[54,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler":[[55,1,1,"","KiwoomOpenApiPlusLoadConditionEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler.KiwoomOpenApiPlusLoadConditionEventHandler":[[55,2,1,"","OnReceiveConditionVer"],[55,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler":[[56,1,1,"","KiwoomOpenApiPlusLoggingEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler.KiwoomOpenApiPlusLoggingEventHandler":[[56,2,1,"","OnEventConnect"],[56,2,1,"","OnReceiveChejanData"],[56,2,1,"","OnReceiveConditionVer"],[56,2,1,"","OnReceiveMsg"],[56,2,1,"","OnReceiveRealCondition"],[56,2,1,"","OnReceiveRealData"],[56,2,1,"","OnReceiveTrCondition"],[56,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler":[[57,1,1,"","KiwoomOpenApiPlusLoginEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler.KiwoomOpenApiPlusLoginEventHandler":[[57,2,1,"","OnEventConnect"],[57,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler":[[58,1,1,"","KiwoomOpenApiPlusAllOrderEventHandler"],[58,1,1,"","KiwoomOpenApiPlusBaseOrderEventHandler"],[58,1,1,"","KiwoomOpenApiPlusOrderEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusBaseOrderEventHandler":[[58,2,1,"","OnEventConnect"],[58,2,1,"","OnReceiveChejanData"],[58,2,1,"","OnReceiveMsg"],[58,2,1,"","OnReceiveTrData"],[58,2,1,"","ResponseForOnReceiveChejanData"],[58,2,1,"","ResponseForOnReceiveMsg"],[58,2,1,"","ResponseForOnReceiveTrData"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler.KiwoomOpenApiPlusOrderEventHandler":[[58,2,1,"","OnReceiveChejanData"],[58,2,1,"","OnReceiveMsg"],[58,2,1,"","OnReceiveTrData"],[58,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler":[[59,1,1,"","KiwoomOpenApiPlusBidirectionalRealEventHandler"],[59,1,1,"","KiwoomOpenApiPlusRealEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusBidirectionalRealEventHandler":[[59,2,1,"","OnReceiveRealData"],[59,2,1,"","consume_request_iterator"],[59,2,1,"","on_enter"],[59,2,1,"","on_exit"],[59,2,1,"","register_code"],[59,2,1,"","remove_all_codes"],[59,2,1,"","remove_all_screens"],[59,2,1,"","remove_code"],[59,2,1,"","start_request_iterator_consumer"],[59,2,1,"","stop_request_iterator_consumer"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler.KiwoomOpenApiPlusRealEventHandler":[[59,2,1,"","OnEventConnect"],[59,2,1,"","OnReceiveRealData"],[59,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler":[[60,1,1,"","KiwoomOpenApiPlusTrEventHandler"]],"koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler.KiwoomOpenApiPlusTrEventHandler":[[60,2,1,"","OnEventConnect"],[60,2,1,"","OnReceiveMsg"],[60,2,1,"","OnReceiveTrData"],[60,2,1,"","on_enter"]],"koapy.backend.kiwoom_open_api_plus.grpc.tools":[[63,0,0,"-","compile_proto"]],"koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto":[[63,5,1,"","compile_proto"]],"koapy.backend.kiwoom_open_api_plus.pyside2":[[66,0,0,"-","KiwoomOpenApiPlusDialogHandler"],[67,0,0,"-","KiwoomOpenApiPlusManagerApplication"],[68,0,0,"-","KiwoomOpenApiPlusServerApplication"],[69,0,0,"-","KiwoomOpenApiPlusSignalHandler"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler":[[66,1,1,"","DialogToHandle"],[66,1,1,"","KiwoomOpenApiPlusDialogHandler"],[66,1,1,"","KiwoomOpenApiPlusDialogToHandle"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.DialogToHandle":[[66,2,1,"","handle"],[66,2,1,"","handle_if_needed"],[66,2,1,"","should_handle"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogHandler":[[66,2,1,"","onReadyDialog"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler.KiwoomOpenApiPlusDialogToHandle":[[66,2,1,"","handle"],[66,2,1,"","handle_by_clicking_button"],[66,2,1,"","handle_by_emiting_should_restart_signal"],[66,2,1,"","handle_if_needed"],[66,2,1,"","should_handle"],[66,2,1,"","should_handle_by_title"],[66,2,1,"","to_specification"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication":[[67,1,1,"","KiwoomOpenApiPlusManagerApplication"],[67,1,1,"","KiwoomOpenApiPlusManagerApplicationArgumentParser"],[67,1,1,"","KiwoomOpenApiPlusServerApplicationProcess"],[67,1,1,"","KiwoomOpenApiPlusServerApplicationSubprocess"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication":[[67,1,1,"","ConnectionStatus"],[67,1,1,"","RestartType"],[67,1,1,"","ServerType"],[67,2,1,"","close"],[67,2,1,"","execAndExit"],[67,2,1,"","exec_"],[67,2,1,"","exit"],[67,2,1,"","main"],[67,2,1,"","restart"],[67,4,1,"","shouldRestart"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.ConnectionStatus":[[67,4,1,"","CONNECTED"],[67,4,1,"","DISCONNECTED"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.RestartType":[[67,4,1,"","NO_RESTART"],[67,4,1,"","RESTART_AND_CONNECT"],[67,4,1,"","RESTART_AND_RESTORE"],[67,4,1,"","RESTART_ONLY"],[67,4,1,"","RESTART_WITH_UPDATE"],[67,4,1,"","RESTART_WITH_UPDATE_AND_CONNECT"],[67,4,1,"","RESTART_WITH_UPDATE_AND_RESTORE"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplication.ServerType":[[67,4,1,"","REAL"],[67,4,1,"","SIMULATION"],[67,4,1,"","UNKNOWN"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusManagerApplicationArgumentParser":[[67,2,1,"","parse_args"],[67,2,1,"","parse_known_args"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication.KiwoomOpenApiPlusServerApplicationSubprocess":[[67,2,1,"","close"],[67,2,1,"","start"],[67,2,1,"","waitForFinished"],[67,2,1,"","waitForStarted"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication":[[68,1,1,"","KiwoomOpenApiPlusServerApplication"],[68,1,1,"","KiwoomOpenApiPlusServerApplicationArgumentParser"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplication":[[68,1,1,"","ConnectionStatus"],[68,1,1,"","ServerType"],[68,2,1,"","execAndExit"],[68,2,1,"","exec_"],[68,2,1,"","exit"],[68,2,1,"","main"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplication.ConnectionStatus":[[68,4,1,"","CONNECTED"],[68,4,1,"","DISCONNECTED"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplication.ServerType":[[68,4,1,"","REAL"],[68,4,1,"","SIMULATION"],[68,4,1,"","UNKNOWN"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication.KiwoomOpenApiPlusServerApplicationArgumentParser":[[68,2,1,"","parse_args"],[68,2,1,"","parse_known_args"]],"koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler":[[69,1,1,"","KiwoomOpenApiPlusSignalHandler"]],"koapy.backend.kiwoom_open_api_plus.utils":[[72,0,0,"-","grpc"],[74,0,0,"-","list_conversion"],[75,0,0,"-","module_path"],[79,0,0,"-","pyside2"],[83,0,0,"-","queue"]],"koapy.backend.kiwoom_open_api_plus.utils.grpc":[[71,0,0,"-","PipeableMultiThreadedRendezvous"]],"koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous":[[71,1,1,"","PipeableMultiThreadedRendezvous"]],"koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous.PipeableMultiThreadedRendezvous":[[71,2,1,"","pipe"]],"koapy.backend.kiwoom_open_api_plus.utils.list_conversion":[[74,5,1,"","convert_list_arguments"],[74,5,1,"","list_to_string"],[74,5,1,"","string_to_list"]],"koapy.backend.kiwoom_open_api_plus.utils.module_path":[[75,5,1,"","GetAPIModulePath"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2":[[76,0,0,"-","QDialogHandler"],[77,0,0,"-","QSignalHandler"],[78,0,0,"-","QThreadPoolExecutor"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler":[[76,1,1,"","QDialogHandler"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler.QDialogHandler":[[76,2,1,"","from_titles"],[76,2,1,"","get_text_of_dialog"],[76,4,1,"","notReadyDialog"],[76,4,1,"","readyDialog"],[76,2,1,"","run"],[76,2,1,"","stop"],[76,2,1,"","wait_for_termination"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler":[[77,1,1,"","QSignalHandler"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler.QSignalHandler":[[77,2,1,"","emitSignal"],[77,2,1,"","onReadyRead"],[77,2,1,"","restoreAll"],[77,2,1,"","restoreAllHandlers"],[77,2,1,"","restoreHandler"],[77,2,1,"","restoreWakeUpFileDescrptor"],[77,2,1,"","setAll"],[77,2,1,"","setHandler"],[77,2,1,"","setWakeUpFileDescriptor"],[77,4,1,"","signaled"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor":[[78,1,1,"","QThreadPoolExecutor"],[78,1,1,"","QThreadPoolExecutorRunnable"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutor":[[78,2,1,"","shutdown"],[78,2,1,"","submit"]],"koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor.QThreadPoolExecutorRunnable":[[78,2,1,"","run"]],"koapy.backend.kiwoom_open_api_plus.utils.queue":[[80,0,0,"-","QueueBasedBufferedIterator"],[81,0,0,"-","QueueBasedIterableObserver"],[82,0,0,"-","QueueIterator"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator":[[80,1,1,"","QueueBasedBufferedIterator"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator.QueueBasedBufferedIterator":[[80,2,1,"","next"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver":[[81,1,1,"","QueueBasedIterableObserver"],[81,1,1,"","QueueBasedIterableObserverIterator"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserver":[[81,2,1,"","on_completed"],[81,2,1,"","on_error"],[81,2,1,"","on_next"],[81,2,1,"","queue"],[81,2,1,"","stop"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver.QueueBasedIterableObserverIterator":[[81,2,1,"","head"],[81,2,1,"","next"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator":[[82,1,1,"","BufferedQueueIterator"],[82,1,1,"","QueueIterator"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.BufferedQueueIterator":[[82,2,1,"","has_next"],[82,2,1,"","head"],[82,2,1,"","next"]],"koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator.QueueIterator":[[82,2,1,"","enable"],[82,2,1,"","has_next"],[82,2,1,"","next"],[82,2,1,"","next_nowait"],[82,2,1,"","queue"],[82,2,1,"","stop"]],"koapy.backend.kiwoom_open_api_w":[[94,0,0,"-","core"]],"koapy.backend.kiwoom_open_api_w.core":[[84,0,0,"-","KiwoomOpenApiWDynamicCallable"],[85,0,0,"-","KiwoomOpenApiWEntrypoint"],[86,0,0,"-","KiwoomOpenApiWError"],[87,0,0,"-","KiwoomOpenApiWEventHandler"],[88,0,0,"-","KiwoomOpenApiWEventHandlerFunctions"],[89,0,0,"-","KiwoomOpenApiWLoggingEventHandler"],[90,0,0,"-","KiwoomOpenApiWQAxWidget"],[91,0,0,"-","KiwoomOpenApiWQAxWidgetMixin"],[92,0,0,"-","KiwoomOpenApiWSignalConnector"],[93,0,0,"-","KiwoomOpenApiWSignature"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable":[[84,1,1,"","KiwoomOpenApiWDynamicCallable"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable.KiwoomOpenApiWDynamicCallable":[[84,2,1,"","is_valid_return_type"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError":[[86,3,1,"","KiwoomOpenApiWBooleanReturnCodeError"],[86,3,1,"","KiwoomOpenApiWError"],[86,3,1,"","KiwoomOpenApiWNegativeReturnCodeError"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWBooleanReturnCodeError":[[86,4,1,"","OP_ERR_FAILURE"],[86,4,1,"","OP_ERR_SUCCESS"],[86,2,1,"","check_code_or_raise"],[86,2,1,"","code"],[86,2,1,"","try_or_raise"],[86,2,1,"","wrap_to_check_code_or_raise"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWError":[[86,2,1,"","message"],[86,2,1,"","try_or_raise"],[86,2,1,"","try_or_raise_boolean"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError.KiwoomOpenApiWNegativeReturnCodeError":[[86,4,1,"","ERROR_MESSAGE_BY_CODE"],[86,4,1,"","MSG_ERR_CONNECT"],[86,4,1,"","MSG_ERR_LOGIN"],[86,4,1,"","MSG_ERR_NONE"],[86,4,1,"","MSG_ERR_NO_LOGIN"],[86,4,1,"","MSG_ERR_NO_REGOPENAPI"],[86,4,1,"","MSG_ERR_ORDER_OVERFLOW"],[86,4,1,"","MSG_ERR_ORD_WRONG_ACCNO"],[86,4,1,"","MSG_ERR_ORD_WRONG_ACCPWD"],[86,4,1,"","MSG_ERR_ORD_WRONG_INPUT"],[86,4,1,"","MSG_ERR_ORD_WRONG_QTY200"],[86,4,1,"","MSG_ERR_ORD_WRONG_QTY400"],[86,4,1,"","MSG_ERR_RQ_WRONG_INPUT"],[86,4,1,"","MSG_ERR_SISE_OVERFLOW"],[86,4,1,"","MSG_ERR_TRCODE"],[86,4,1,"","MSG_ERR_VERSION"],[86,4,1,"","OP_ERR_CONNECT"],[86,4,1,"","OP_ERR_LOGIN"],[86,4,1,"","OP_ERR_NONE"],[86,4,1,"","OP_ERR_NO_LOGIN"],[86,4,1,"","OP_ERR_NO_REGOPENAPI"],[86,4,1,"","OP_ERR_ORDER_OVERFLOW"],[86,4,1,"","OP_ERR_ORD_WRONG_ACCNO"],[86,4,1,"","OP_ERR_ORD_WRONG_ACCPWD"],[86,4,1,"","OP_ERR_ORD_WRONG_INPUT"],[86,4,1,"","OP_ERR_ORD_WRONG_QTY200"],[86,4,1,"","OP_ERR_ORD_WRONG_QTY400"],[86,4,1,"","OP_ERR_RQ_WRONG_INPUT"],[86,4,1,"","OP_ERR_SISE_OVERFLOW"],[86,4,1,"","OP_ERR_TRCODE"],[86,4,1,"","OP_ERR_VERSION"],[86,2,1,"","check_code_or_raise"],[86,2,1,"","code"],[86,2,1,"","get_error_message_by_code"],[86,2,1,"","try_or_raise"],[86,2,1,"","wrap_to_check_code_or_raise"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler":[[87,1,1,"","KiwoomOpenApiWEventHandler"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler.KiwoomOpenApiWEventHandler":[[87,2,1,"","add_callback"],[87,2,1,"","close"],[87,2,1,"","connect"],[87,2,1,"","control"],[87,2,1,"","disconnect"],[87,2,1,"","enter"],[87,2,1,"","exit"],[87,2,1,"","names"],[87,2,1,"","observer"],[87,2,1,"","on_enter"],[87,2,1,"","on_exit"],[87,2,1,"","slots"],[87,2,1,"","stop"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions":[[88,1,1,"","KiwoomOpenApiWEventHandlerFunctions"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions.KiwoomOpenApiWEventHandlerFunctions":[[88,2,1,"","OnEventConnect"],[88,2,1,"","OnReceiveChejanData"],[88,2,1,"","OnReceiveMsg"],[88,2,1,"","OnReceiveRealData"],[88,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler":[[89,1,1,"","KiwoomOpenApiWLoggingEventHandler"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler.KiwoomOpenApiWLoggingEventHandler":[[89,2,1,"","OnEventConnect"],[89,2,1,"","OnReceiveChejanData"],[89,2,1,"","OnReceiveMsg"],[89,2,1,"","OnReceiveRealData"],[89,2,1,"","OnReceiveTrData"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget":[[90,1,1,"","KiwoomOpenApiWQAxWidget"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget.KiwoomOpenApiWQAxWidget":[[90,4,1,"","CLSID"],[90,4,1,"","EVENT_NAMES"],[90,4,1,"","METHOD_NAMES"],[90,2,1,"","changeEvent"],[90,2,1,"","closeEvent"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin":[[91,1,1,"","KiwoomOpenApiWQAxWidgetMixin"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector":[[92,1,1,"","KiwoomOpenApiWSignalConnector"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector.KiwoomOpenApiWSignalConnector":[[92,2,1,"","call"],[92,2,1,"","connect"],[92,2,1,"","connect_to"],[92,2,1,"","disconnect"],[92,2,1,"","is_valid_slot"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature":[[93,5,1,"","BuildOleItems"],[93,6,1,"","DISPATCH_SIGNATURES_BY_NAME"],[93,6,1,"","EVENT_HANDLER_SIGNATURES_BY_NAME"],[93,1,1,"","KiwoomOpenApiWDispatchSignature"],[93,1,1,"","KiwoomOpenApiWEventHandlerSignature"],[93,1,1,"","KiwoomOpenApiWSignature"],[93,5,1,"","LoadDispatchSignatures"],[93,5,1,"","LoadEventHandlerSignatures"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWDispatchSignature":[[93,4,1,"","DISPATCH_SIGNATURES_BY_NAME"],[93,2,1,"","from_name"],[93,2,1,"","names"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWEventHandlerSignature":[[93,4,1,"","EVENT_HANDLER_SIGNATURES_BY_NAME"],[93,2,1,"","from_name"],[93,2,1,"","names"]],"koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature.KiwoomOpenApiWSignature":[[93,4,1,"","COMTYPE_TO_PYTHONTYPE"],[93,4,1,"","DISPATCH_CLSID"],[93,4,1,"","EVENT_CLSID"],[93,4,1,"","MODULE_CLSID"],[93,4,1,"","OLE_ITEMS"],[93,4,1,"","PYTHONTYPE_TO_QTTYPE"],[93,2,1,"","name"],[93,2,1,"","to_pyside2_event_signal"],[93,2,1,"","to_pyside2_function_prototype"]],"koapy.backtrader":[[96,0,0,"-","KiwoomOpenApiPlusBroker"],[97,0,0,"-","KiwoomOpenApiPlusData"],[98,0,0,"-","KiwoomOpenApiPlusEventStreamer"],[99,0,0,"-","KiwoomOpenApiPlusStore"],[100,0,0,"-","KrxHistoricalDailyPriceData"],[101,0,0,"-","KrxHistoricalDailyPriceDataFromSQLite"],[102,0,0,"-","KrxTradingCalendar"],[103,0,0,"-","SQLAlchemyData"],[104,0,0,"-","SQLAlchemySQLiteData"],[105,0,0,"-","SQLiteData"]],"koapy.backtrader.KiwoomOpenApiPlusBroker":[[96,1,1,"","KiwoomOpenApiPlusBroker"],[96,1,1,"","KiwoomOpenApiPlusCommInfo"],[96,1,1,"","MetaKiwoomOpenApiPlusBroker"]],"koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusBroker":[[96,2,1,"","add_order_history"],[96,2,1,"","buy"],[96,2,1,"","cancel"],[96,2,1,"","data_started"],[96,2,1,"","get_notification"],[96,2,1,"","getcash"],[96,2,1,"","getposition"],[96,2,1,"","getvalue"],[96,2,1,"","next"],[96,2,1,"","notify"],[96,2,1,"","orderstatus"],[96,4,1,"","params"],[96,2,1,"","sell"],[96,2,1,"","set_fund_history"],[96,2,1,"","start"],[96,2,1,"","stop"],[96,2,1,"","submit"]],"koapy.backtrader.KiwoomOpenApiPlusBroker.KiwoomOpenApiPlusCommInfo":[[96,4,1,"","params"]],"koapy.backtrader.KiwoomOpenApiPlusData":[[97,1,1,"","KiwoomOpenApiPlusData"],[97,1,1,"","MetaKiwoomOpenApiPlusData"]],"koapy.backtrader.KiwoomOpenApiPlusData.KiwoomOpenApiPlusData":[[97,2,1,"","asutc"],[97,2,1,"","date2num"],[97,2,1,"","fromtimestamp"],[97,2,1,"","haslivedata"],[97,2,1,"","islive"],[97,2,1,"","isnaive"],[97,2,1,"","num2date"],[97,4,1,"","params"],[97,2,1,"","setenvironment"],[97,2,1,"","start"],[97,2,1,"","stop"]],"koapy.backtrader.KiwoomOpenApiPlusEventStreamer":[[98,1,1,"","KiwoomOpenApiPlusEventStreamer"],[98,1,1,"","KiwoomOpenApiPlusOrderEventChannel"],[98,1,1,"","KiwoomOpenApiPlusPriceEventChannel"],[98,1,1,"","MetaKiwoomOpenApiPlusEventStreamer"]],"koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusEventStreamer":[[98,2,1,"","events"],[98,2,1,"","on_completed"],[98,2,1,"","on_error"],[98,2,1,"","on_next"],[98,2,1,"","rates"]],"koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusOrderEventChannel":[[98,2,1,"","close"],[98,2,1,"","convert_to_dict"],[98,2,1,"","event_to_dict"],[98,2,1,"","filter_chejan_response"],[98,2,1,"","get_observable"],[98,2,1,"","is_chejan_response"]],"koapy.backtrader.KiwoomOpenApiPlusEventStreamer.KiwoomOpenApiPlusPriceEventChannel":[[98,2,1,"","close"],[98,2,1,"","convert_to_dict"],[98,2,1,"","event_to_dict"],[98,2,1,"","filter_for_code"],[98,2,1,"","filter_price_event"],[98,2,1,"","get_observable_for_code"],[98,2,1,"","initialize"],[98,2,1,"","is_for_code"],[98,2,1,"","is_valid_price_event"],[98,2,1,"","register_code"],[98,2,1,"","time_to_timestamp"]],"koapy.backtrader.KiwoomOpenApiPlusStore":[[99,1,1,"","API"],[99,1,1,"","HistoricalPriceRecord"],[99,3,1,"","KiwoomOpenApiPlusJsonError"],[99,1,1,"","KiwoomOpenApiPlusStore"],[99,3,1,"","KiwoomOpenApiPlusTimeFrameError"],[99,1,1,"","MetaKiwoomOpenApiPlusStore"],[99,1,1,"","MetaSingleton"]],"koapy.backtrader.KiwoomOpenApiPlusStore.API":[[99,2,1,"","close_order"],[99,2,1,"","create_order"],[99,2,1,"","get_account"],[99,2,1,"","get_history"],[99,2,1,"","get_instruments"],[99,2,1,"","get_instruments_original"],[99,2,1,"","get_positions"],[99,2,1,"","get_today_quotes_by_code"]],"koapy.backtrader.KiwoomOpenApiPlusStore.HistoricalPriceRecord":[[99,2,1,"","dict_records_from_dataframe"],[99,2,1,"","from_tuple"],[99,2,1,"","records_from_dataframe"]],"koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusJsonError":[[99,2,1,"","error_response"]],"koapy.backtrader.KiwoomOpenApiPlusStore.KiwoomOpenApiPlusStore":[[99,4,1,"","BrokerCls"],[99,4,1,"","DataCls"],[99,2,1,"","broker_threads"],[99,2,1,"","candles"],[99,2,1,"","get_cash"],[99,2,1,"","get_granularity"],[99,2,1,"","get_instrument"],[99,2,1,"","get_notifications"],[99,2,1,"","get_positions"],[99,2,1,"","get_value"],[99,2,1,"","getbroker"],[99,2,1,"","getdata"],[99,2,1,"","initial_today_historical_msg"],[99,2,1,"","order_cancel"],[99,2,1,"","order_create"],[99,4,1,"","params"],[99,2,1,"","put_notification"],[99,2,1,"","start"],[99,2,1,"","stop"],[99,2,1,"","streaming_events"],[99,2,1,"","streaming_prices"],[99,2,1,"","timeoffset"]],"koapy.backtrader.KrxHistoricalDailyPriceData":[[100,1,1,"","KrxHistoricalDailyPriceData"]],"koapy.backtrader.KrxHistoricalDailyPriceData.KrxHistoricalDailyPriceData":[[100,2,1,"","adddata_fromfile"],[100,4,1,"","lines"],[100,4,1,"","params"],[100,2,1,"","start"],[100,2,1,"","stop"]],"koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite":[[101,1,1,"","KrxHistoricalDailyPriceDataFromSQLite"]],"koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite.KrxHistoricalDailyPriceDataFromSQLite":[[101,2,1,"","adddata_fromfile"],[101,2,1,"","dump_from_store"],[101,4,1,"","lines"],[101,4,1,"","params"]],"koapy.backtrader.KrxTradingCalendar":[[102,1,1,"","ExchangeCalendarsTradingCalendar"],[102,1,1,"","KrxTradingCalendar"]],"koapy.backtrader.KrxTradingCalendar.ExchangeCalendarsTradingCalendar":[[102,4,1,"","params"],[102,2,1,"","schedule"]],"koapy.backtrader.KrxTradingCalendar.KrxTradingCalendar":[[102,4,1,"","params"]],"koapy.backtrader.SQLAlchemyData":[[103,1,1,"","SQLAlchemyData"]],"koapy.backtrader.SQLAlchemyData.SQLAlchemyData":[[103,4,1,"","params"],[103,2,1,"","start"],[103,2,1,"","stop"]],"koapy.backtrader.SQLAlchemySQLiteData":[[104,1,1,"","SQLAlchemySQLiteData"]],"koapy.backtrader.SQLAlchemySQLiteData.SQLAlchemySQLiteData":[[104,4,1,"","params"]],"koapy.backtrader.SQLiteData":[[105,1,1,"","SQLiteData"]],"koapy.backtrader.SQLiteData.SQLiteData":[[105,4,1,"","params"],[105,2,1,"","start"],[105,2,1,"","stop"]],"koapy.cli":[[107,0,0,"-","__main__"],[152,5,1,"","cli"],[137,0,0,"-","commands"],[152,6,1,"","context_settings"],[152,6,1,"","default_encoding"],[152,5,1,"","disable"],[152,5,1,"","enable"],[149,0,0,"-","extensions"],[152,5,1,"","fail_with_usage"],[152,5,1,"","generate"],[152,5,1,"","get"],[152,5,1,"","get_credentials"],[152,5,1,"","get_logger"],[152,6,1,"","help_option_names"],[152,5,1,"","install"],[152,6,1,"","logger"],[152,5,1,"","login"],[152,5,1,"","main"],[152,5,1,"","order"],[152,6,1,"","order_types"],[152,6,1,"","quote_types"],[152,5,1,"","serve"],[152,5,1,"","show"],[152,5,1,"","uninstall"],[152,5,1,"","update"],[156,0,0,"-","utils"],[152,5,1,"","verbose_option"],[152,5,1,"","watch"]],"koapy.cli.commands":[[109,0,0,"-","disable"],[111,0,0,"-","enable"],[114,0,0,"-","generate"],[125,0,0,"-","get"],[138,0,0,"-","install"],[141,0,0,"-","serve"],[143,0,0,"-","show"],[144,0,0,"-","uninstall"],[147,0,0,"-","update"]],"koapy.cli.commands.disable":[[109,5,1,"","auto_login"],[108,0,0,"-","auto_login"],[109,5,1,"","disable"]],"koapy.cli.commands.disable.auto_login":[[108,5,1,"","auto_login"],[108,5,1,"","disable_auto_login_after_login"],[108,5,1,"","disable_auto_login_without_login"]],"koapy.cli.commands.enable":[[111,5,1,"","auto_login"],[110,0,0,"-","auto_login"],[111,5,1,"","enable"]],"koapy.cli.commands.enable.auto_login":[[110,5,1,"","auto_login"]],"koapy.cli.commands.generate":[[114,5,1,"","generate"],[114,5,1,"","grpc"],[112,0,0,"-","grpc"],[115,0,0,"-","openapi"]],"koapy.cli.commands.generate.grpc":[[112,5,1,"","grpc"],[113,0,0,"-","ssl_credentials"]],"koapy.cli.commands.generate.grpc.ssl_credentials":[[113,5,1,"","generate_key_cert_signed_by_authority"],[113,5,1,"","generate_self_signed_key_cert"],[113,5,1,"","ssl_credentials"]],"koapy.cli.commands.generate.openapi":[[115,5,1,"","openapi"],[116,0,0,"-","python_stubs"]],"koapy.cli.commands.generate.openapi.python_stubs":[[116,6,1,"","default_dispatch_class_name"],[116,6,1,"","default_dispatch_file_path"],[116,6,1,"","default_event_class_name"],[116,6,1,"","default_event_file_path"],[116,5,1,"","python_stubs"]],"koapy.cli.commands.get":[[119,0,0,"-","account_data"],[123,0,0,"-","chart_data"],[125,5,1,"","codelist"],[125,5,1,"","daily"],[125,5,1,"","deposit"],[125,5,1,"","errmsg"],[125,5,1,"","evaluation"],[125,5,1,"","get"],[125,5,1,"","minute"],[125,5,1,"","modulepath"],[127,0,0,"-","openapi_meta"],[125,5,1,"","orders"],[125,5,1,"","realinfo"],[133,0,0,"-","stock_meta"],[125,5,1,"","stockcode"],[125,5,1,"","stockinfo"],[125,5,1,"","stockname"],[125,5,1,"","trinfo"],[125,5,1,"","userinfo"]],"koapy.cli.commands.get.account_data":[[117,0,0,"-","deposit"],[118,0,0,"-","evaluation"],[120,0,0,"-","orders"],[121,0,0,"-","userinfo"]],"koapy.cli.commands.get.account_data.deposit":[[117,5,1,"","deposit"],[117,6,1,"","logger"]],"koapy.cli.commands.get.account_data.evaluation":[[118,5,1,"","evaluation"],[118,6,1,"","logger"]],"koapy.cli.commands.get.account_data.orders":[[120,6,1,"","logger"],[120,5,1,"","orders"]],"koapy.cli.commands.get.account_data.userinfo":[[121,5,1,"","userinfo"]],"koapy.cli.commands.get.chart_data":[[122,0,0,"-","daily"],[124,0,0,"-","minute"]],"koapy.cli.commands.get.chart_data.daily":[[122,5,1,"","daily"],[122,6,1,"","logger"]],"koapy.cli.commands.get.chart_data.minute":[[124,6,1,"","logger"],[124,5,1,"","minute"],[124,6,1,"","minute_intervals"]],"koapy.cli.commands.get.openapi_meta":[[126,0,0,"-","errmsg"],[128,0,0,"-","modulepath"],[129,0,0,"-","realinfo"],[130,0,0,"-","trinfo"]],"koapy.cli.commands.get.openapi_meta.errmsg":[[126,5,1,"","errmsg"]],"koapy.cli.commands.get.openapi_meta.modulepath":[[128,5,1,"","modulepath"]],"koapy.cli.commands.get.openapi_meta.realinfo":[[129,5,1,"","realinfo"]],"koapy.cli.commands.get.openapi_meta.trinfo":[[130,5,1,"","trinfo"]],"koapy.cli.commands.get.stock_meta":[[131,0,0,"-","codelist"],[132,0,0,"-","codelist_interactive"],[134,0,0,"-","stockcode"],[135,0,0,"-","stockinfo"],[136,0,0,"-","stockname"]],"koapy.cli.commands.get.stock_meta.codelist":[[131,5,1,"","codelist"],[131,5,1,"","main"],[131,6,1,"","market_codes"]],"koapy.cli.commands.get.stock_meta.codelist_interactive":[[132,1,1,"","MarketEntry"],[132,1,1,"","Screen"],[132,1,1,"","StatusBarHandler"],[132,1,1,"","StockEntry"],[132,5,1,"","codelist_interactive"],[132,5,1,"","main"],[132,6,1,"","markets"],[132,5,1,"","screen_len"],[132,5,1,"","wrapper"]],"koapy.cli.commands.get.stock_meta.codelist_interactive.MarketEntry":[[132,2,1,"","to_string"]],"koapy.cli.commands.get.stock_meta.codelist_interactive.Screen":[[132,2,1,"","refresh_footer_bar"],[132,2,1,"","refresh_header_bar"],[132,2,1,"","set_footer_bar"],[132,2,1,"","set_header_bar"],[132,2,1,"","show_entries"]],"koapy.cli.commands.get.stock_meta.codelist_interactive.StatusBarHandler":[[132,2,1,"","emit"]],"koapy.cli.commands.get.stock_meta.codelist_interactive.StockEntry":[[132,2,1,"","to_string"]],"koapy.cli.commands.get.stock_meta.stockcode":[[134,6,1,"","market_codes"],[134,5,1,"","stockcode"]],"koapy.cli.commands.get.stock_meta.stockinfo":[[135,5,1,"","stockinfo"]],"koapy.cli.commands.get.stock_meta.stockname":[[136,5,1,"","stockname"]],"koapy.cli.commands.install":[[138,5,1,"","install"],[139,0,0,"-","openapi"],[140,0,0,"-","pywin32"]],"koapy.cli.commands.install.openapi":[[139,6,1,"","logger"],[139,5,1,"","openapi"]],"koapy.cli.commands.install.pywin32":[[140,5,1,"","pywin32"]],"koapy.cli.commands.serve":[[141,5,1,"","full_verbose_option"],[141,5,1,"","grpc_server_and_client_options"],[141,5,1,"","serve"]],"koapy.cli.commands.show":[[143,5,1,"","account_window"],[142,0,0,"-","account_window"],[143,5,1,"","show"]],"koapy.cli.commands.show.account_window":[[142,5,1,"","account_window"]],"koapy.cli.commands.uninstall":[[145,0,0,"-","openapi"],[146,0,0,"-","pywin32"],[144,5,1,"","uninstall"]],"koapy.cli.commands.uninstall.openapi":[[145,6,1,"","logger"],[145,5,1,"","openapi"]],"koapy.cli.commands.uninstall.pywin32":[[146,5,1,"","pywin32"]],"koapy.cli.commands.update":[[147,5,1,"","get_credentials"],[147,5,1,"","openapi"],[147,5,1,"","proto"],[147,5,1,"","realtype"],[147,5,1,"","trinfo"],[147,5,1,"","update"],[147,5,1,"","verbose_option"]],"koapy.cli.extensions":[[148,0,0,"-","functools"],[150,0,0,"-","parser"],[151,0,0,"-","verbose_option"]],"koapy.cli.extensions.functools":[[148,5,1,"","update_wrapper_with_click_params"]],"koapy.cli.extensions.parser":[[150,6,1,"","ArgumentDecorator"],[150,1,1,"","ArgumentParser"],[150,1,1,"","ClickArgumentParser"],[150,6,1,"","CommandDecorator"],[150,6,1,"","Function"],[150,6,1,"","FunctionOrCommand"]],"koapy.cli.extensions.parser.ArgumentParser":[[150,2,1,"","parse_args"],[150,2,1,"","parse_known_args"]],"koapy.cli.extensions.parser.ClickArgumentParser":[[150,2,1,"","parse_args"],[150,2,1,"","parse_known_args"]],"koapy.cli.extensions.verbose_option":[[151,1,1,"","VerboseOption"],[151,5,1,"","no_verbose_flag_option"],[151,5,1,"","verbose_flag_option"],[151,5,1,"","verbose_option"]],"koapy.cli.extensions.verbose_option.VerboseOption":[[151,2,1,"","add_to_parser"]],"koapy.cli.utils":[[153,0,0,"-","credentials"],[154,0,0,"-","fail_with_usage"],[155,0,0,"-","grpc_options"],[157,0,0,"-","openapi"],[158,0,0,"-","pywin32"],[159,0,0,"-","verbose_option"]],"koapy.cli.utils.credentials":[[153,5,1,"","get_credentials"],[153,5,1,"","prompt_credentials"]],"koapy.cli.utils.fail_with_usage":[[154,5,1,"","fail_with_usage"],[154,5,1,"","get_help"],[154,5,1,"","get_help_without_usage"]],"koapy.cli.utils.grpc_options":[[155,6,1,"","client_argument_parser"],[155,6,1,"","client_cert_file_option"],[155,6,1,"","client_enable_ssl_option"],[155,6,1,"","client_host_option"],[155,6,1,"","client_key_file_option"],[155,6,1,"","client_options"],[155,6,1,"","client_port_option"],[155,6,1,"","client_root_certs_file_option"],[155,6,1,"","default_client_host"],[155,6,1,"","default_client_port"],[155,6,1,"","default_common_host"],[155,6,1,"","default_common_port"],[155,6,1,"","default_server_bind_address"],[155,6,1,"","default_server_host"],[155,6,1,"","default_server_port"],[155,5,1,"","grpc_client_options"],[155,6,1,"","grpc_config"],[155,5,1,"","grpc_server_and_client_options"],[155,5,1,"","grpc_server_options"],[155,6,1,"","server_and_client_argument_parser"],[155,6,1,"","server_and_client_bind_address_option"],[155,6,1,"","server_and_client_client_cert_file_option"],[155,6,1,"","server_and_client_client_key_file_option"],[155,6,1,"","server_and_client_client_root_certs_file_option"],[155,6,1,"","server_and_client_enable_ssl_option"],[155,6,1,"","server_and_client_host_option"],[155,6,1,"","server_and_client_no_require_client_auth_option"],[155,6,1,"","server_and_client_options"],[155,6,1,"","server_and_client_port_option"],[155,6,1,"","server_and_client_require_client_auth_option"],[155,6,1,"","server_and_client_server_cert_file_option"],[155,6,1,"","server_and_client_server_key_file_option"],[155,6,1,"","server_and_client_server_root_certs_file_option"],[155,6,1,"","server_argument_parser"],[155,6,1,"","server_bind_address_option"],[155,6,1,"","server_cert_file_option"],[155,6,1,"","server_key_file_option"],[155,6,1,"","server_no_require_client_auth_option"],[155,6,1,"","server_options"],[155,6,1,"","server_port_option"],[155,6,1,"","server_require_client_auth_option"],[155,6,1,"","server_root_certs_file_option"]],"koapy.cli.utils.openapi":[[157,5,1,"","download_openapi_installer"],[157,6,1,"","iss_file_encoding"],[157,6,1,"","logger"],[157,5,1,"","prepare_issfile_for_install"],[157,5,1,"","prepare_issfile_for_uninstall"],[157,5,1,"","run_installer_with_issfile"]],"koapy.cli.utils.pywin32":[[158,5,1,"","get_pywin32_postinstall_script"],[158,5,1,"","install_pywin32"],[158,6,1,"","logger"],[158,5,1,"","uninstall_pywin32"]],"koapy.cli.utils.verbose_option":[[159,5,1,"","full_verbose_option"],[159,6,1,"","full_verbosity"],[159,5,1,"","verbose_option"],[159,5,1,"","verbose_option_callback"]],"koapy.compat":[[166,0,0,"-","pyside2"],[169,0,0,"-","pywinauto"]],"koapy.compat.pyside2":[[166,6,1,"","QT_QPA_PLATFORM_PLUGIN_PATH"],[161,0,0,"-","QtAxContainer"],[162,0,0,"-","QtCore"],[163,0,0,"-","QtGui"],[164,0,0,"-","QtNetwork"],[165,0,0,"-","QtWidgets"],[166,6,1,"","config"],[166,6,1,"","debug"],[166,5,1,"","get_logger"],[166,6,1,"","logger"]],"koapy.compat.pywinauto":[[169,1,1,"","PyWinAutoFinder"],[167,0,0,"-","findwindows"],[168,0,0,"-","importlib"],[170,0,0,"-","timings"]],"koapy.compat.pywinauto.PyWinAutoFinder":[[169,2,1,"","find_spec"],[169,2,1,"","register"],[169,2,1,"","unregister"]],"koapy.compat.pywinauto.importlib":[[168,1,1,"","PyWinAutoFinder"],[168,1,1,"","PyWinAutoLoader"]],"koapy.compat.pywinauto.importlib.PyWinAutoFinder":[[168,2,1,"","find_spec"],[168,2,1,"","register"],[168,2,1,"","unregister"]],"koapy.compat.pywinauto.importlib.PyWinAutoLoader":[[168,2,1,"","create_module"],[168,2,1,"","exec_module"],[168,2,1,"","reset_sys_coinit_flags"],[168,2,1,"","set_sys_coinit_flags"]],"koapy.config":[[171,6,1,"","Config"],[171,6,1,"","config"],[171,5,1,"","config_from_dict"],[171,6,1,"","current_working_directory"],[171,6,1,"","debug"],[171,6,1,"","default_config"],[171,6,1,"","default_config_file_directory"],[171,6,1,"","default_config_filename"],[171,6,1,"","default_config_filepath"],[171,6,1,"","default_encoding"],[171,6,1,"","default_user_config_filename"],[171,6,1,"","default_user_config_filepath"],[171,5,1,"","dump_config"],[171,6,1,"","empty_config"],[171,5,1,"","find_user_config_file_from"],[171,5,1,"","find_user_config_file_in"],[171,5,1,"","get_32bit_executable"],[171,5,1,"","get_64bit_executable"],[171,5,1,"","get_config"],[171,5,1,"","get_executable_from_conda_envname"],[171,5,1,"","get_executable_from_conda_envpath"],[171,5,1,"","get_executable_from_executable_config"],[171,5,1,"","get_user_config"],[171,6,1,"","home_directory"],[171,5,1,"","initialize_config_from_expected_paths"],[171,5,1,"","initialize_config_from_given_path"],[171,5,1,"","read_config"],[171,5,1,"","save_config"],[171,5,1,"","save_user_config"],[171,5,1,"","set_user_config"],[171,6,1,"","user_config"],[171,6,1,"","user_config_filename_cadidates"]],"koapy.utils":[[173,0,0,"-","builtin"],[174,0,0,"-","ctypes"],[179,0,0,"-","data"],[180,0,0,"-","datetime"],[181,0,0,"-","exchange_calendars"],[182,0,0,"-","grpc"],[184,0,0,"-","itertools"],[186,0,0,"-","logging"],[196,0,0,"-","messaging"],[197,0,0,"-","networking"],[198,0,0,"-","notimplemented"],[199,0,0,"-","platform"],[200,0,0,"-","pywin32"],[202,0,0,"-","rate_limiting"],[205,0,0,"-","recursion"],[206,0,0,"-","serialization"],[210,0,0,"-","store"],[222,0,0,"-","subprocess"],[223,0,0,"-","threading"]],"koapy.utils.builtin":[[173,5,1,"","dir_public"]],"koapy.utils.ctypes":[[174,5,1,"","is_admin"]],"koapy.utils.data":[[179,1,1,"","KrxHistoricalDailyPriceDataDownloader"],[175,0,0,"-","KrxHistoricalDailyPriceDataDownloader"],[179,1,1,"","KrxHistoricalDailyPriceDataForBacktestLoader"],[176,0,0,"-","KrxHistoricalDailyPriceDataForBacktestLoader"],[179,1,1,"","KrxHistoricalDailyPriceDataLoader"],[177,0,0,"-","KrxHistoricalDailyPriceDataLoader"],[178,0,0,"-","YahooFinanceKrxHistoricalDailyPriceDataDownloader"]],"koapy.utils.data.KrxHistoricalDailyPriceDataDownloader":[[175,1,1,"","KrxHistoricalDailyPriceDataDownloader"],[179,2,1,"","download"],[179,2,1,"","get_full_code"],[179,2,1,"","get_name"],[179,2,1,"","get_stocks"],[179,2,1,"","get_stocks_delisted"],[179,2,1,"","stocks"],[179,2,1,"","stocks_delisted"]],"koapy.utils.data.KrxHistoricalDailyPriceDataDownloader.KrxHistoricalDailyPriceDataDownloader":[[175,2,1,"","download"],[175,2,1,"","get_full_code"],[175,2,1,"","get_name"],[175,2,1,"","get_stocks"],[175,2,1,"","get_stocks_delisted"],[175,2,1,"","stocks"],[175,2,1,"","stocks_delisted"]],"koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader":[[176,1,1,"","KrxHistoricalDailyPriceDataForBacktestLoader"],[179,2,1,"","adjust_data"],[179,2,1,"","get_adjust_ratios"],[179,2,1,"","get_symbols"],[179,2,1,"","load"],[179,2,1,"","load_as_cursor"],[179,2,1,"","update"]],"koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader.KrxHistoricalDailyPriceDataForBacktestLoader":[[176,2,1,"","adjust_data"],[176,2,1,"","get_adjust_ratios"],[176,2,1,"","get_symbols"],[176,2,1,"","load"],[176,2,1,"","load_as_cursor"],[176,2,1,"","update"]],"koapy.utils.data.KrxHistoricalDailyPriceDataLoader":[[177,1,1,"","KrxHistoricalDailyPriceDataLoader"],[179,2,1,"","load"],[179,2,1,"","load_from_database"],[179,2,1,"","load_or_download"],[179,2,1,"","symbols"],[179,2,1,"","symbols_delisted"],[179,2,1,"","update"]],"koapy.utils.data.KrxHistoricalDailyPriceDataLoader.KrxHistoricalDailyPriceDataLoader":[[177,2,1,"","load"],[177,2,1,"","load_from_database"],[177,2,1,"","load_or_download"],[177,2,1,"","symbols"],[177,2,1,"","symbols_delisted"],[177,2,1,"","update"]],"koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader":[[178,1,1,"","YahooFinanceKrxHistoricalDailyPriceDataDownloader"]],"koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader.YahooFinanceKrxHistoricalDailyPriceDataDownloader":[[178,2,1,"","download"]],"koapy.utils.datetime":[[180,5,1,"","is_naive"],[180,5,1,"","localize"]],"koapy.utils.exchange_calendars":[[181,6,1,"","calendar"],[181,6,1,"","day"],[181,5,1,"","get_last_session_date"],[181,5,1,"","is_currently_in_session"],[181,6,1,"","name"]],"koapy.utils.grpc":[[182,5,1,"","cancel_after"],[182,5,1,"","pprint_message"],[182,5,1,"","warn_on_rpc_error"],[182,5,1,"","warn_on_rpc_error_context"]],"koapy.utils.itertools":[[184,5,1,"","chunk"]],"koapy.utils.logging":[[186,1,1,"","Logging"],[185,0,0,"-","Logging"],[186,5,1,"","get_logger"],[186,5,1,"","get_loglevel"],[186,5,1,"","get_package_logger"],[186,5,1,"","get_verbosity"],[186,5,1,"","loglevel_to_verbosity"],[191,0,0,"-","pyside2"],[186,5,1,"","set_loglevel"],[186,5,1,"","set_verbosity"],[193,0,0,"-","tqdm"],[186,5,1,"","verbosity_to_loglevel"]],"koapy.utils.logging.Logging":[[185,1,1,"","Logging"],[185,1,1,"","LoggingMeta"],[186,2,1,"","logger"]],"koapy.utils.logging.Logging.Logging":[[185,2,1,"","logger"]],"koapy.utils.logging.Logging.LoggingMeta":[[185,2,1,"","get_class_logger"],[185,2,1,"","get_logger"],[185,2,1,"","get_loglevel"],[185,2,1,"","get_module_logger"],[185,2,1,"","get_package_logger"],[185,2,1,"","get_verbosity"],[185,2,1,"","logger"],[185,2,1,"","loglevel_to_verbosity"],[185,2,1,"","set_loglevel"],[185,2,1,"","set_verbosity"],[185,2,1,"","verbosity_to_loglevel"]],"koapy.utils.logging.pyside2":[[187,0,0,"-","QAbstractSocketLogging"],[188,0,0,"-","QObjectLogging"],[189,0,0,"-","QThreadLogging"],[190,0,0,"-","QWidgetLogging"]],"koapy.utils.logging.pyside2.QAbstractSocketLogging":[[187,1,1,"","QAbstractSocketLogging"],[187,1,1,"","QAbstractSocketLoggingMeta"]],"koapy.utils.logging.pyside2.QObjectLogging":[[188,1,1,"","QObjectLogging"],[188,1,1,"","QObjectLoggingMeta"]],"koapy.utils.logging.pyside2.QThreadLogging":[[189,1,1,"","QThreadLogging"],[189,1,1,"","QThreadLoggingMeta"]],"koapy.utils.logging.pyside2.QWidgetLogging":[[190,1,1,"","QWidgetLogging"],[190,1,1,"","QWidgetLoggingMeta"]],"koapy.utils.logging.tqdm":[[192,0,0,"-","TqdmStreamHandler"]],"koapy.utils.logging.tqdm.TqdmStreamHandler":[[192,1,1,"","TqdmStreamHandler"]],"koapy.utils.messaging":[[194,0,0,"-","DiscordMessenger"],[195,0,0,"-","Messenger"]],"koapy.utils.messaging.DiscordMessenger":[[194,1,1,"","DiscordWebhookMessenger"],[194,1,1,"","DoItYourselfDiscordWebhookMessenger"]],"koapy.utils.messaging.DiscordMessenger.DiscordWebhookMessenger":[[194,2,1,"","send_message"]],"koapy.utils.messaging.DiscordMessenger.DoItYourselfDiscordWebhookMessenger":[[194,2,1,"","send_message"]],"koapy.utils.messaging.Messenger":[[195,1,1,"","Messenger"]],"koapy.utils.messaging.Messenger.Messenger":[[195,2,1,"","send_message"]],"koapy.utils.networking":[[197,5,1,"","find_free_port_for_host"],[197,5,1,"","get_free_localhost_port"],[197,5,1,"","is_in_private_network"]],"koapy.utils.notimplemented":[[198,5,1,"","isimplemented"],[198,5,1,"","isnotimplemented"],[198,5,1,"","notimplemented"]],"koapy.utils.platform":[[199,5,1,"","is_32bit"],[199,5,1,"","is_64bit"],[199,5,1,"","is_windows"]],"koapy.utils.pywin32":[[200,5,1,"","BuildOleItems"],[200,5,1,"","GetLatestTypelibSpec"],[200,5,1,"","GetTypelibSpecs"],[200,5,1,"","IsPyIID"],[200,5,1,"","IsPyIIDLike"],[200,5,1,"","IsPyITypeLib"],[200,5,1,"","LoadTypeLib"],[200,6,1,"","PyIID"],[200,6,1,"","PyIIDLike"],[200,6,1,"","PyITypeLib"]],"koapy.utils.rate_limiting":[[201,0,0,"-","RateLimiter"],[204,0,0,"-","pyside2"]],"koapy.utils.rate_limiting.RateLimiter":[[201,1,1,"","CompositeTimeWindowRateLimiter"],[201,1,1,"","RateLimiter"],[201,1,1,"","TimeWindowRateLimiter"]],"koapy.utils.rate_limiting.RateLimiter.CompositeTimeWindowRateLimiter":[[201,2,1,"","add_call_history"],[201,2,1,"","check_sleep_seconds"],[201,2,1,"","sleep_if_necessary"]],"koapy.utils.rate_limiting.RateLimiter.RateLimiter":[[201,2,1,"","add_call_history"],[201,2,1,"","check_sleep_seconds"],[201,2,1,"","sleep_if_necessary"],[201,2,1,"","wrap"]],"koapy.utils.rate_limiting.RateLimiter.TimeWindowRateLimiter":[[201,2,1,"","add_call_history"],[201,2,1,"","check_sleep_seconds"],[201,2,1,"","sleep_if_necessary"]],"koapy.utils.rate_limiting.pyside2":[[203,0,0,"-","QRateLimitedExecutor"]],"koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor":[[203,1,1,"","QRateLimitedExecutor"],[203,1,1,"","QRateLimitedExecutorDecoratedFunction"],[203,1,1,"","QRateLimitedExecutorRunnable"]],"koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutor":[[203,2,1,"","onReadyRunnable"],[203,4,1,"","readyRunnable"],[203,2,1,"","run"],[203,2,1,"","shutdown"],[203,2,1,"","submit"],[203,2,1,"","wrap"]],"koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorDecoratedFunction":[[203,2,1,"","async_call"],[203,2,1,"","call"]],"koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor.QRateLimitedExecutorRunnable":[[203,2,1,"","add_call_history"],[203,2,1,"","cancel"],[203,2,1,"","check_sleep_seconds"],[203,2,1,"","result"],[203,2,1,"","run"],[203,2,1,"","sleep_if_necessary"]],"koapy.utils.recursion":[[205,5,1,"","depth"]],"koapy.utils.serialization":[[206,1,1,"","JsonSerializable"]],"koapy.utils.serialization.JsonSerializable":[[206,2,1,"","from_dict"],[206,2,1,"","from_json"],[206,2,1,"","to_dict"],[206,2,1,"","to_json"]],"koapy.utils.store":[[207,0,0,"-","SQLiteFileLibrary"],[210,1,1,"","SQLiteStore"],[208,0,0,"-","SQLiteStore"],[209,0,0,"-","SQLiteStoreLibrary"],[212,0,0,"-","misc"],[221,0,0,"-","sqlalchemy"]],"koapy.utils.store.SQLiteFileLibrary":[[207,1,1,"","SQLiteFileLibrary"]],"koapy.utils.store.SQLiteFileLibrary.SQLiteFileLibrary":[[207,2,1,"","delete"],[207,2,1,"","has_symbol"],[207,2,1,"","list_symbols"],[207,2,1,"","read"],[207,2,1,"","read_as_cursor"],[207,2,1,"","read_as_dataframe"],[207,2,1,"","write"]],"koapy.utils.store.SQLiteStore":[[208,1,1,"","SQLiteStore"],[210,2,1,"","delete_library"],[210,2,1,"","get_library"],[210,2,1,"","get_or_create_library"],[210,2,1,"","initialize_library"],[210,2,1,"","library_exists"],[210,2,1,"","list_libraries"]],"koapy.utils.store.SQLiteStore.SQLiteStore":[[208,2,1,"","delete_library"],[208,2,1,"","get_library"],[208,2,1,"","get_or_create_library"],[208,2,1,"","initialize_library"],[208,2,1,"","library_exists"],[208,2,1,"","list_libraries"]],"koapy.utils.store.SQLiteStoreLibrary":[[209,1,1,"","SQLiteStoreLibrary"]],"koapy.utils.store.SQLiteStoreLibrary.SQLiteStoreLibrary":[[209,2,1,"","delete"],[209,2,1,"","delete_snapshot"],[209,2,1,"","has_symbol"],[209,2,1,"","list_snapshots"],[209,2,1,"","list_symbols"],[209,2,1,"","list_versions"],[209,2,1,"","read"],[209,2,1,"","read_as_cursor"],[209,2,1,"","read_as_dataframe"],[209,2,1,"","snapshot"],[209,2,1,"","write"]],"koapy.utils.store.misc":[[211,0,0,"-","VersionedItem"]],"koapy.utils.store.misc.VersionedItem":[[211,1,1,"","VersionedItem"]],"koapy.utils.store.sqlalchemy":[[213,0,0,"-","Base"],[214,0,0,"-","Library"],[215,0,0,"-","Session"],[216,0,0,"-","Snapshot"],[217,0,0,"-","SnapshotAssociation"],[218,0,0,"-","Symbol"],[219,0,0,"-","Timestamp"],[220,0,0,"-","Version"]],"koapy.utils.store.sqlalchemy.Base":[[213,6,1,"","Base"]],"koapy.utils.store.sqlalchemy.Library":[[214,1,1,"","Library"]],"koapy.utils.store.sqlalchemy.Library.Library":[[214,2,1,"","create_snapshot"],[214,2,1,"","delete"],[214,2,1,"","get_latest_versions"],[214,2,1,"","get_or_create_symbol"],[214,2,1,"","get_snapshot"],[214,2,1,"","get_symbol"],[214,2,1,"","get_symbols"],[214,2,1,"","get_versions"],[214,4,1,"","id"],[214,4,1,"","name"],[214,4,1,"","snapshots"],[214,4,1,"","symbols"]],"koapy.utils.store.sqlalchemy.Session":[[215,6,1,"","Session"]],"koapy.utils.store.sqlalchemy.Snapshot":[[216,1,1,"","Snapshot"]],"koapy.utils.store.sqlalchemy.Snapshot.Snapshot":[[216,2,1,"","delete"],[216,2,1,"","get_symbols"],[216,2,1,"","get_version_of_symbol"],[216,2,1,"","get_versions"],[216,4,1,"","id"],[216,4,1,"","library"],[216,4,1,"","library_id"],[216,4,1,"","name"],[216,4,1,"","timestamp"],[216,4,1,"","versions"]],"koapy.utils.store.sqlalchemy.SnapshotAssociation":[[217,1,1,"","SnapshotAssociation"]],"koapy.utils.store.sqlalchemy.SnapshotAssociation.SnapshotAssociation":[[217,4,1,"","snapshot"],[217,4,1,"","snapshot_id"],[217,4,1,"","version"],[217,4,1,"","version_id"]],"koapy.utils.store.sqlalchemy.Symbol":[[218,1,1,"","Symbol"]],"koapy.utils.store.sqlalchemy.Symbol.Symbol":[[218,2,1,"","create_new_version"],[218,2,1,"","get_latest_version"],[218,2,1,"","get_prunable_versions"],[218,2,1,"","get_version_by_number"],[218,2,1,"","get_versions"],[218,4,1,"","id"],[218,4,1,"","library"],[218,4,1,"","library_id"],[218,4,1,"","name"],[218,4,1,"","versions"]],"koapy.utils.store.sqlalchemy.Timestamp":[[219,1,1,"","Timestamp"]],"koapy.utils.store.sqlalchemy.Timestamp.Timestamp":[[219,4,1,"","cache_ok"],[219,4,1,"","impl"],[219,2,1,"","is_naive"],[219,4,1,"","local_timezone"],[219,2,1,"","process_bind_param"],[219,2,1,"","process_result_value"],[219,4,1,"","signature"],[219,4,1,"","utc"]],"koapy.utils.store.sqlalchemy.Version":[[220,1,1,"","Version"]],"koapy.utils.store.sqlalchemy.Version.Version":[[220,2,1,"","delete"],[220,4,1,"","deleted"],[220,2,1,"","get_snapshots"],[220,4,1,"","id"],[220,4,1,"","pandas_metadata"],[220,4,1,"","snapshots"],[220,4,1,"","symbol"],[220,4,1,"","symbol_id"],[220,4,1,"","table_name"],[220,4,1,"","timestamp"],[220,4,1,"","user_metadata"],[220,4,1,"","version"]],"koapy.utils.subprocess":[[222,1,1,"","Popen"],[222,5,1,"","create_job_object_for_cleanup"],[222,5,1,"","function_to_script"],[222,5,1,"","function_to_subprocess_args"],[222,6,1,"","job_handle"],[222,6,1,"","logger"],[222,5,1,"","make_process_die_when_parent_dies"],[222,5,1,"","quote"],[222,5,1,"","run_as_admin"],[222,5,1,"","run_file"],[222,5,1,"","run_function"],[222,5,1,"","run_script"]],"koapy.utils.threading":[[223,1,1,"","Singleton"]],"koapy.utils.threading.Singleton":[[223,2,1,"","get_instance"]],koapy:[[15,0,0,"-","backend"],[106,0,0,"-","backtrader"],[152,0,0,"-","cli"],[160,0,0,"-","compat"],[171,0,0,"-","config"],[183,0,0,"-","utils"]]},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","exception","Python exception"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:exception","4":"py:attribute","5":"py:function","6":"py:data"},terms:{"0":[3,17,22,23,29,45,49,67,68,86,96,97,99,125,131,134,151,185,205,218,226,228,230,232],"00":[17,45,152,228,230,231,232],"0000":[230,231,232],"000000":[228,230],"0000000":230,"00000000":[230,231],"0000000000":[230,232],"000020":231,"000040":231,"000050":231,"000060":231,"000070":231,"0001":[230,231,232],"000240":[230,231],"000\uc6d0":228,"001":[17,228],"001800":[230,231],"001880":[230,231],"002":17,"002170":[230,231],"003":17,"003230":[230,231],"003550":[230,231],"004":17,"004000":[230,231],"005":17,"005930":[228,230,231,232],"006":17,"006040":[230,231],"006390":[230,231],"006650":[230,231],"007":[17,230],"007236":228,"007310":230,"007700":[230,231],"008":[17,228],"008876":228,"009":17,"009970":[230,231],"01":[228,230,232],"010":17,"0101":17,"011":17,"011780":[230,231],"012":[17,232],"013":17,"014":17,"014830":[230,231],"015":[17,96],"016":[17,232],"0163911":230,"017":17,"017241":228,"017890":[230,231],"017960":230,"018":17,"02":[226,228,230,232],"020000":[230,231],"021240":[230,231],"023600":231,"025":230,"025540":[230,231],"026548":228,"03":[17,45,152,228,230,231,232],"030520":[230,231],"031343":228,"033290":[230,231],"033780":[230,231],"035420":228,"036190":[230,231],"036830":[230,231],"037":228,"037710":[230,231],"038":228,"039490":17,"04":[17,228,230,232],"042420":[230,231],"043":228,"049070":230,"049430":[230,231],"049458":228,"049845":228,"05":[17,45,152,228,230],"050":228,"051":228,"052":228,"056190":[230,231],"057050":[230,231],"06":[17,45,152,228,230],"060150":[230,231],"062627":228,"064":228,"064960":[230,231],"069080":[230,231],"069158":228,"06fd":93,"07":[17,45,152,226,228,230],"073560":[230,231],"08":[17,228,230,232],"081660":[230,231],"084650":230,"089":230,"09":[17,228,230,231],"090003":230,"095660":[230,231],"096530":[230,231],"0\uc73c\ub85c":17,"0\uc744":17,"0\uc774\uba70":23,"0\uc774\uba74":17,"0\uc785\ub825":17,"0a":231,"0x1c66d09af70":230,"0x1c66e74e040":230,"1":[1,3,17,22,23,28,29,37,45,49,67,68,86,96,124,151,152,218,219,226,227,228,230,231,232],"10":[17,45,124,125,131,134,152,227,228,230,231,232],"100":[17,23,228,230,231,232],"1000":[228,230,231],"100000":230,"100015":230,"1000\ud68c\ub85c":228,"1001":[230,231],"10010":230,"1002":[230,231],"10023":[230,231],"10024":[230,231],"1003":[230,231],"1004":[230,231],"1005":[230,231],"100500":230,"1006":[230,231],"1008":231,"1009":[230,231],"10096725":230,"100\uac1c":17,"100\uc744":17,"100\uc885\ubaa9":17,"100\uc885\ubaa9\uae4c\uc9c0":17,"100\uc885\ubaa9\uc744":30,"101":[23,231],"1015":228,"101500":230,"101615":230,"10171":230,"101j9000":17,"101jc000":17,"102":[23,230],"10200":230,"10250":230,"1030":230,"10300":230,"1031":230,"1032":230,"10350":230,"103500":230,"10400":230,"10450":230,"1045138":228,"10475":228,"1047713":228,"105":228,"10500":[228,230],"10550":230,"10600":230,"10650":230,"1071":230,"1072":230,"10770":231,"108":230,"10820":231,"10834":230,"108583":230,"1088598":230,"109":230,"10930":231,"10931":230,"1094780000":228,"10960":231,"10\uac1c\uae4c\uc9c0":30,"10\uac1c\ub9cc":230,"10\ub144\uad6d\ucc44":17,"10\ubd84":17,"10\uc5f0\uc18d":30,"10\uc790\ub9ac":[17,45,230,231],"10\ucd08":230,"11":[17,228,230,231],"110":230,"11000502":230,"1102":231,"11042":230,"110790":[230,231],"11145":230,"111770":[230,231],"11200":230,"1124":228,"11250":230,"11256":228,"11300":230,"11350":230,"11400":230,"11450":230,"115":230,"11500":230,"1155":230,"11550":230,"116":228,"1160":230,"11600":230,"116046":230,"1165":230,"11650":230,"11657":228,"117":228,"1170":230,"11700":230,"1171968":230,"1175":230,"11750":230,"11810":[230,231],"11814":230,"1185":230,"11850":230,"1190":230,"119377":228,"1195":230,"119649":231,"11\uc6d4\ubb3c":17,"11\uc77c":228,"12":[17,228,230,231,232],"120":[218,230,231],"1200":230,"1205":230,"120500":230,"1210":230,"1215":230,"1220":230,"1225":230,"12253":230,"1230":230,"12300":231,"123110":230,"1234":232,"1234567890":232,"1234931":230,"1235":230,"123643":228,"123651":230,"124":228,"1240":230,"12441":230,"1245":230,"12450":231,"125":228,"1250":230,"125488":228,"126":230,"12647":230,"1267":230,"1271":230,"12730034":231,"12750":230,"12800":230,"12850":230,"12900":230,"12919230000":228,"12930":[230,231],"12950":230,"129500":231,"12957":230,"12960208":228,"12976730":231,"13":[17,45,152,228,230,231],"130":230,"1300":231,"13000":230,"1300000":17,"13050":230,"130500":231,"131":[228,230],"13100":230,"1313":230,"1314":230,"1314506":231,"1315":230,"13150":230,"1316":230,"13190221":228,"1320":230,"13200":230,"1320880":228,"13250":230,"133453":230,"13350":230,"134":230,"13400":231,"135":230,"1350":230,"13500":[230,231],"1354":228,"13550":230,"135513":231,"13580":230,"13600":230,"13650":230,"13699":230,"1370":230,"13700":230,"137310":[230,231],"1375":230,"13750":230,"1380":230,"13800":230,"1381":228,"13818":230,"1385":230,"13850":230,"13889401":230,"1389":228,"138975":230,"139":230,"1390":230,"13900":230,"13950":230,"139526":228,"1398":230,"14":[228,230,231],"140":[230,231],"1400":230,"14000":230,"140000":230,"140126":230,"1405":[228,230],"14057369":228,"140910":[230,231],"141":228,"1410":230,"1412":17,"1415":230,"14150":230,"1417":230,"1420":230,"14200":231,"142000":230,"142341":230,"1425":230,"14250":231,"142555":230,"142598":230,"142607":230,"142708":230,"142725":230,"142750":230,"142810":230,"142825":230,"142830":230,"142834":230,"142838":230,"142845":230,"142850":230,"142851":230,"142901":230,"142905":230,"142908":230,"142912":230,"142913":230,"142914":230,"142919":230,"142920":230,"142921":230,"142924":230,"142940":230,"142941":230,"142942":230,"142943":230,"142945":230,"142946":230,"142947":230,"143":230,"1430":[228,230],"14306854":228,"1435":230,"14350":230,"144":230,"1440":230,"1445":[228,230],"14450":[230,231],"1449":228,"1459":228,"146":230,"14600":231,"1462":228,"1465":[228,230],"147":232,"147191":230,"1475":230,"14766":230,"1478":230,"1485":230,"149":232,"14900":230,"1497":230,"1498":230,"15":[17,124,219,228,230,231],"150":[230,231],"1500":228,"15000":230,"1504":230,"1505":230,"15050":230,"150\uc77c":228,"151":[228,230],"1515":228,"152":[17,230],"1520":228,"15214":230,"1530":228,"1537":230,"1540":230,"154300":230,"154419":228,"1550":230,"1551":230,"1552586":231,"1558":228,"15600":231,"1563680000":228,"157000":228,"1575":230,"157600":228,"157800":228,"158000":228,"158200":228,"158400":228,"158600":228,"15891":230,"159":228,"1590":230,"15900":230,"159000":228,"159200":228,"159419":231,"1598":228,"15983654":228,"15\ucd08\uc5d0":[5,228],"16":[17,45,152,228,230,231],"160":[228,230,231],"1600":[230,231],"1601":[230,231],"1603685":231,"1604":[230,231],"1605":[230,231],"1608":[230,231],"1610":[230,231],"16100":230,"1611":[230,231],"161390":[230,231],"1614":[230,231],"161890":[230,231],"162":228,"162170":230,"1622":228,"162500":230,"16267327":228,"1629":228,"16299":230,"1630":[230,231],"16350":230,"1640":228,"164049085":228,"1648":228,"165":[228,231],"1651290000":228,"1657":230,"1660":[228,230,231],"16600":230,"1665":228,"167":230,"1670":231,"1671":228,"167500":230,"1683":[230,231],"1684":[230,231],"169000":230,"1691":228,"16939411":228,"169500":230,"17":[17,227,228,230,231],"170":[228,230],"1700":[230,231],"170000":230,"1703":228,"1705":228,"170500":230,"170929":228,"1710":[230,231],"171000":230,"171105175500":228,"171179000000":228,"171500":230,"17200":230,"172000":230,"17219":230,"1724":228,"1725":230,"172500":230,"173":230,"173000":230,"173500":230,"174":230,"1743":228,"1744":231,"1745":231,"1746":231,"1747":231,"1748":231,"1749":231,"175000":230,"1755":228,"175828":230,"1759":228,"1763":228,"176574":230,"17744721":231,"1777":[228,230],"1789":228,"179":230,"179000":230,"1793":228,"1797":228,"17\ucd08\ub300\uae30":30,"18":[17,228,230,231,232],"180":[230,231],"180692":230,"180\ucd08":30,"181519":228,"182":[228,230],"1827":230,"18280":231,"1829":228,"18350":[230,231],"18373668":228,"18400":231,"18450":230,"184853":230,"1849":230,"1850":230,"1855":230,"185750":[230,231],"186":231,"18614":228,"18645":231,"1865":228,"187400":230,"1875":228,"18750":[230,231],"187501":230,"187870":[230,231],"18810":231,"1890":230,"1891":230,"1892":230,"18925":231,"189904":230,"19":[228,230,231,232],"190":228,"1900":230,"19050":230,"19104":230,"1912":228,"1916":227,"192":230,"192080":[230,231],"1921":230,"1923":228,"192400":[230,231],"192440":[230,231],"19245":228,"19250":231,"1936":230,"1951":228,"19600":230,"1961":228,"197":[228,230],"1970":219,"1973":228,"1979":228,"1980":228,"1983":228,"1985":[228,230],"19850104":[230,231],"19850105":[230,231],"19850107":[230,231],"19850108":[230,231],"19850109":[230,231],"1987":[228,230],"1989":[228,230],"1990":228,"19900":230,"1991":[228,230],"1993":[228,230],"1995":[228,230],"19950":230,"1996":228,"1997":[228,230],"1998":228,"1999":228,"1\uac74":230,"1\ub144\uce58":228,"1\ub85c":17,"1\ubc88":30,"1\ubd84\uc5d0":[30,230],"1\uc2dc\uac04\ub2f9":228,"1\uc774\uba74":17,"1\uc8fc":[230,231],"1\ucd08\ub2f9":[30,228],"1\ucd08\uc5d0":[17,30,228],"1\ud68c":[48,228],"1\ud68c\ub85c":30,"1d":228,"1eda98188ffc":93,"1f8a15":93,"1line":231,"2":[3,17,23,29,45,49,67,68,152,227,228,230,232],"20":[17,45,152,228,230,231,232],"200":[17,32,230,231],"2000":[228,230],"20000":230,"2000\uac74\uc758":228,"2000\ub144":228,"2001":228,"200130":[230,231],"2002":[228,230],"20021029":228,"20021030":228,"20021031":228,"20021101":228,"20021104":228,"2003":228,"2004":228,"2005":[228,230],"20050":230,"2007":[228,230],"2007\ub144\ubd80\ud130":228,"2008":228,"2009":[219,228,230],"2009\ub144":228,"2009\ub144\uc5d0":228,"200\uac1c":86,"201":[17,230],"2010":228,"20100":230,"2011":228,"2012":[228,230],"20124":230,"2013":228,"2013\ub144\uacfc":228,"2014":[228,230],"201407":17,"201408":17,"201409":17,"201412":17,"2014\ub144":228,"2015":[228,232],"2016":228,"20161214":228,"201639":228,"2017":[228,230],"20170101":45,"20174":230,"2018":228,"2019":[228,230],"201j7260":17,"201j7262":17,"201jc260":17,"202":[17,230],"2020":[17,227,228],"20200":230,"20200120":232,"20200319":232,"2021":[17,228,232],"20210115":230,"20210202":231,"20211013":[230,231],"2022":[226,228,230],"20220110":228,"20220111":228,"20220112":[228,230],"20220113":[228,230],"20220114":[228,230],"20220117":230,"20220118":230,"20220126":231,"20220127":231,"20220128":231,"20220203":231,"20220204":231,"20220206":231,"20300":230,"2032":230,"20350":230,"20400":230,"2042":228,"20423":231,"204346":228,"20450":230,"2050":230,"20500":230,"2051":228,"20515":231,"20522":230,"20549":228,"20550":230,"20554":230,"20560":231,"207":228,"20785736":228,"20892185":228,"209":230,"20900":230,"2091":228,"20925":231,"2095":228,"20979":230,"20\uac74\uc73c\ub85c\uc81c\ud55c":5,"20\ub144":228,"20\uc5b5\uc6d0\uc744":22,"21":[228,230,231],"210":230,"210540":[230,231],"211":230,"2110":230,"2115":230,"211j8045":17,"2120":230,"2125":230,"213":230,"2130":230,"2133":228,"2135":[228,230],"21367447":231,"2140":230,"2145":230,"215":230,"2150":230,"215490":230,"2155":230,"2160":230,"21600":230,"21606":230,"2170":[228,230],"217389":232,"2188":228,"219000":230,"2191":228,"22":[228,230,231,232],"220":[230,231],"2200":228,"22000":228,"221":231,"2214":228,"2215":228,"222":[230,231],"2221":228,"2222":228,"222500":230,"22255":230,"2227":228,"22274777":231,"223":231,"22372":228,"224":[230,231],"22400":[230,231],"225":231,"225220":[230,231],"2253":228,"22546156":228,"226074":228,"22650":230,"227":[228,230],"22700":230,"22750":230,"22800":230,"2283":228,"2285":228,"22850":230,"22900":230,"22942":230,"22950":230,"2298":228,"23":[17,45,152,228,230,231],"2300":[228,230,231],"23000":230,"230165":231,"2304":228,"2304009":232,"2305":228,"23050":230,"2309":228,"231":230,"23100":230,"2312":228,"2323":228,"2339":228,"2344":228,"2349":228,"235":228,"2350":230,"2351":230,"236":230,"236322868506":228,"236323":228,"236323000000":228,"2368070":[230,231],"23750":230,"2377":230,"238":230,"23807":230,"23861":228,"2396":228,"2398":228,"24":[228,230],"240":[230,231],"2400":230,"24037":230,"240610":230,"242808":228,"243":230,"243070":231,"2438":228,"2448":230,"2450":228,"2456":228,"2459":228,"24600":230,"24640":230,"24672":230,"24732368":228,"2485":230,"2492":228,"249415":231,"2499":228,"25":[96,228,230,231],"250":[228,231],"2500":228,"25000":230,"250\ucd5c\uace0":[230,231,232],"250\ucd5c\uace0\uac00\ub300\ube44\uc728":[230,231,232],"250\ucd5c\uace0\uac00\uc77c":[230,231,232],"250\ucd5c\uc800":[230,231,232],"250\ucd5c\uc800\uac00\ub300\ube44\uc728":[230,231,232],"250\ucd5c\uc800\uac00\uc77c":[230,231,232],"25171310":228,"2519":228,"2520":228,"254":[228,230],"254358":230,"255":228,"2556":228,"2558":228,"256":[228,230],"2563":228,"25634775":228,"257":230,"2584":228,"2587":228,"2588":228,"2598":228,"2599":228,"26":[17,45,152,228,230,231],"260":[17,230,231],"2600":228,"262":230,"2622":230,"2624":228,"2626":228,"2630":228,"263690":231,"264078":[230,231],"2643":228,"2648":230,"2649":230,"26578":230,"266":230,"266293":230,"26650":230,"267":230,"2670":228,"26833":230,"2687":228,"2689":228,"269":230,"2691":228,"27":[228,230,231],"27100":230,"27150":230,"271560":[230,231],"27200":230,"272271":228,"272271000000":228,"272271119021":228,"27250":230,"273":230,"27300":230,"2734":228,"27350":230,"274":228,"27400":230,"27426":230,"2743":230,"2744":230,"2745":230,"27450":230,"2749":230,"27500":230,"2751":230,"27550":230,"27600":230,"2762":230,"276478717500":228,"276479":228,"276479000000":228,"277685":232,"2795":230,"27950":[230,231],"28":[227,228,230,231],"280":[230,231],"28045":230,"28050":[230,231],"281":230,"28277":230,"284740":[230,231],"285130":[230,231],"2856":228,"2857":228,"28650":230,"287":228,"2879":230,"288":228,"289":228,"2890":230,"28951746850":228,"28952":228,"28952000000":228,"29":[228,230,231,232],"2900":228,"29091":230,"29100":230,"291428":230,"291511":228,"293":228,"294":230,"29442":230,"2944634":230,"2944654":230,"2944657":230,"29450":230,"294870":[230,231],"29500":230,"296143":228,"2968":230,"298":5,"29900":230,"2\uc601\uc5c5\uc77c\ub85c":228,"2\uc790\ub9ac":45,"2x":231,"3":[3,17,22,29,45,49,67,68,124,125,131,134,152,224,227,228,230,231,232],"30":[17,124,125,131,134,227,228,230,231],"300":[230,231],"3000":[228,230],"30000":67,"3003":231,"30035":230,"30050":230,"300720":[230,231],"300\uacc4\uc57d":22,"301":227,"30100":230,"30134":231,"30150":230,"302":[230,231],"30200":230,"3021":231,"303":232,"30338":230,"30339":230,"30340":230,"30341":230,"30342":230,"30343":230,"30350":230,"3041":230,"30450":230,"30482":230,"305":[230,231,232],"30500":230,"3053210000":228,"30550":230,"306":[230,231],"30600":230,"30650":230,"307":[230,231],"30750":230,"308":[230,231],"30800":230,"30840":230,"30868":230,"308\uc744":17,"309":[230,231],"30\ub9cc\uc6d0":228,"31":[228,230,231,232],"310":[230,231],"310124985000":228,"3102":230,"311":[228,230,231],"312":[230,231],"31200":230,"314":[228,230,231],"3145356":231,"315":[230,231],"31500":230,"31600":230,"3166":232,"317":231,"31739":230,"31740":230,"31741":230,"3176":230,"318":[231,232],"31850":230,"32":[227,228,230,231],"320":[230,231],"3200":230,"32068":230,"322":[228,230],"32327083":228,"32400":230,"3241":230,"32417":228,"32418":228,"32419":228,"32420":228,"32421":228,"32422":228,"32550":230,"326":230,"326486495000":228,"327230200000":228,"327885440":228,"329":[230,231],"329000":228,"32bit":[227,228,231],"33":[17,228,230],"33050":230,"3306250000":228,"33250":230,"334":230,"334500":228,"335000":228,"3351":230,"335500":228,"3356":230,"336":[230,231],"336000":228,"339000":228,"339364":230,"339500":228,"34":[228,230],"340":[228,230,231],"340000":228,"340500":228,"341":230,"341000":228,"34147":230,"341500":228,"341543":228,"342":230,"342000":228,"342500":228,"342710":228,"344000":228,"34432000000":228,"34432026050":228,"34433":228,"344500":228,"345":230,"345500":228,"346":[230,231],"34600":230,"3467":230,"346712":228,"348000":228,"348053940000":228,"349":230,"3498293":232,"35":[228,230,231],"350":[230,231],"3500":230,"3501":231,"3502":231,"35023":230,"3503":231,"35100":230,"35150":230,"3516":230,"35173":230,"352000":228,"352500":228,"352700":[230,231],"355":228,"356":228,"35600":230,"3564":230,"358":230,"359":230,"35900":231,"359939":[230,231],"36":[227,228,230,231],"360":[230,231],"360097":230,"361":230,"3616":230,"362":230,"363":230,"36300":230,"363165140500":228,"36350":230,"364":230,"364057951000":228,"364058":228,"364058000000":228,"365":[102,230],"365751":228,"366":230,"366274712500":228,"367":230,"36700":231,"369":231,"37":[228,230,232],"370":231,"370406":230,"37048f99b24d":230,"37100":230,"37300":230,"373413":228,"373535":228,"374":230,"375":228,"37500":230,"37528":232,"376":228,"37778":228,"37800":230,"38":[228,230,231,232],"380":[228,230,231],"380859":228,"381":228,"381226":228,"38149":230,"383":228,"3841":[230,231],"384762":228,"3849":228,"389":[230,231],"39":[228,230],"391005952":228,"391591":228,"394":228,"39406":[230,231],"395":228,"396":230,"39666066":228,"3970570000":228,"399":228,"3\ub144\uad6d\ucc44":17,"3\ubc88\uc5d0\uc11c":228,"3\ubd84":30,"3x":227,"4":[3,17,23,29,45,49,67,125,131,134,152,171,227,228,230,231,232],"40":[17,228,230,231],"400":[230,231],"4000":[230,231],"40000":230,"400\uac1c":86,"401":232,"406":232,"40600":230,"40650":228,"407":228,"408":228,"4084":230,"409":230,"41":[228,230,231],"410":230,"4103":230,"4104":230,"411":230,"41100":232,"411584":231,"412":228,"413":228,"414227":230,"415":[228,232],"415778176":228,"41634":230,"41700":228,"42":[228,230,231],"420":[230,231],"42030":228,"42030000000":228,"42030403400":228,"4217":230,"42200":228,"42300":232,"4240":231,"4257":230,"426":228,"427":230,"4280":228,"4292":230,"43":[228,230,231],"431":228,"4310":230,"43150":230,"43200":230,"43300":230,"433baeb2b447":230,"43500":228,"435033":228,"43750":230,"43800":228,"438000":230,"438500":230,"439":228,"43900":228,"43936":230,"43950":230,"44":[228,230,231],"440":[230,231],"44000":[228,230],"44032":228,"44036":[228,230],"440430":228,"44050":230,"44057":228,"44061":230,"44100":230,"44141":228,"44144":228,"44148":230,"44150":230,"44160":230,"44163":[228,230],"44172":228,"4417639":231,"44192":228,"44200":230,"44201":228,"44222":228,"44250":230,"44276961":228,"44277":228,"44284":228,"44288":228,"443":230,"44300":230,"44350":230,"44368":228,"44396":228,"44397":228,"444":228,"44400":230,"44428":[228,230],"444522":228,"44488":230,"4450781":232,"44536":228,"44550":230,"44552":228,"4456888":230,"4459119":231,"44592":[228,230],"44600":230,"44620":228,"447":228,"449":228,"45":[124,228,230,231,232],"450":230,"451":230,"454":228,"455":228,"45650":228,"457":228,"45716":228,"45768":228,"45796":228,"45817":228,"45824":228,"45900":230,"45912":228,"45936":[228,230],"4596733":230,"46":[228,230,231],"460":[230,231],"46020":228,"4602702":230,"460725":230,"46112":228,"46278":230,"46300":228,"46308":228,"46523":228,"46800":228,"46880":232,"46980":230,"47":[228,230],"470":230,"4700":230,"47000":228,"47140":228,"47196":228,"472":228,"47250":230,"473":232,"474":230,"47484":228,"4749":228,"475":228,"4750":228,"4751":228,"4752":228,"4753":228,"47532":[228,230],"4754":228,"47564":228,"476":[228,232],"47673":228,"47732":228,"47803":228,"47900":230,"47928":230,"47960":228,"47973":230,"48":[228,230],"480":[228,230,231],"48000":228,"4802":228,"48036":230,"48152":[228,230],"48155":228,"48169":228,"4817707":230,"4817969":230,"4817972":230,"4817973":230,"4817983":230,"4817984":230,"48260":230,"48264":228,"48277":228,"48324":228,"48372":228,"48376":[228,230],"487":228,"48700":228,"48708":228,"4889":230,"488f":93,"49":[228,230],"49106":231,"49250":228,"49324":[228,230],"49341":228,"49345":[228,230],"49353":230,"49373":230,"494":230,"49400":230,"49436":[228,230],"49450":231,"49457":230,"49500":228,"49548":228,"49549":[228,230],"49550":230,"496674048":228,"49688":[228,230],"49689":228,"4970":[230,231],"49750":230,"49828":228,"49884":[228,230],"49885":228,"49888":228,"49892":[228,230],"49895":228,"499":[228,230],"49e4":90,"4\uc790\ub9ac":[17,45,230,231],"4\ucd08\ub2f9":228,"4\ud68c":228,"4bd7":[28,232],"4cef":93,"4d5a":93,"4f84":93,"5":[17,29,45,49,67,97,124,125,131,134,151,152,159,219,228,230,231,232],"50":[17,125,131,134,228,230,231],"500":[228,230,231],"5000":230,"50000":228,"50024":228,"500252":230,"500\uacc4\uc57d":22,"501745":228,"502":230,"503181":228,"503520":228,"504034":228,"504250":228,"505":[228,230],"50500":228,"50526":228,"50557":228,"506":228,"50612":228,"50619":228,"50629":228,"50640":228,"50644":230,"50672":228,"50696":[228,230],"50732":228,"50752":228,"507732":228,"50808":228,"50836":230,"50857":[228,230],"50864":228,"50867":228,"50868":228,"50880":[228,230],"50896":228,"50937":228,"50948":[228,230],"509886":230,"50997":228,"50\ubc30\uac00":228,"50\uc5b5\uc6d0\uc744":22,"51":[227,228,230,232],"510":230,"51004":228,"51008":228,"51012":228,"51032":228,"51060":[228,230],"51064":[228,230],"51068":[228,230],"51076":228,"51080":228,"51088":228,"51109":228,"51200":228,"51201":228,"51217":230,"51221":228,"51228":228,"51256":228,"51312":230,"51339":228,"51400":231,"51452":[228,230],"51613":[228,230],"51648":228,"51656":228,"51800":230,"52":[228,230,231,232],"520":[230,231],"523":230,"52376":[228,230],"52397":230,"52404":[228,230],"5250":228,"52828":228,"52845":230,"5289":231,"53":[228,230,231,232],"530":228,"53100":230,"53104":230,"532":228,"532843":228,"533":228,"534":230,"53412":[228,230],"535":230,"53552":[228,230],"5356":230,"53560":228,"53596":228,"53600":230,"5363":230,"537":228,"538":228,"5383":230,"53944":[228,230],"54":[228,230],"540":[230,231],"54000":230,"54100":230,"54168":228,"54252":[228,230],"54300":230,"54408":228,"54616":[228,230],"54620":228,"54632":230,"54644":228,"54664":228,"54665":230,"5482":230,"54869":228,"54876":228,"54956443475000":228,"55":[228,230],"553":230,"5530":230,"553345":228,"5537":228,"554":[228,230],"5549":231,"558":230,"56":[228,230,232],"560":[230,231],"56037":230,"56104787070000":228,"5620":228,"56200":230,"56285":230,"564":230,"564413":228,"56484":231,"566":228,"56620":230,"56678958867500":228,"567":[230,231],"568":[228,230,231],"5683":230,"56962":230,"57":[228,230],"57089081580000":228,"571":228,"57100":230,"57170":231,"572":[228,230],"57200":230,"573":230,"57300":230,"57400":230,"57500":230,"57600":230,"57700":230,"57800":230,"57900":230,"58":[228,230],"580":[230,231],"58000":230,"580010":231,"580031":231,"580032":231,"580033":231,"58032":231,"581":230,"583":231,"58500":230,"58600":232,"58660":231,"587":228,"5872":230,"5877689":231,"59":[228,230],"590018":231,"5907":230,"5911":230,"592":230,"595861":230,"5959":230,"596069":228,"5960884":230,"596313":228,"5969783":[230,231,232],"5\uac1c":17,"5\ub144\uad6d\ucc44":17,"5\uc5f0\uc18d":30,"5\ud68c":30,"5\ud68c\ub77c\uace0":228,"5\ud68c\ub9cc":[17,30],"5ff57f5030ae":93,"6":[17,45,67,125,131,134,152,228,230,231,232],"60":[99,124,228,230,231],"600":[228,230,231],"6000":[228,230],"600000000":228,"600\uac74":228,"600\ub9cc\uc6d0":228,"600\ub9cc\uc6d0\uc774\ub2e4":228,"60141":230,"604":230,"60450":230,"606":[228,230],"608869":230,"608871":230,"608891":230,"608892":230,"60\uac74\uc73c\ub85c\uc81c\ud55c":5,"60\ud68c":228,"61":[17,45,152,228,230],"6118":230,"613468":230,"6159":230,"617087":228,"62":[17,45,152,228,230],"620":[230,231],"62100":230,"6214":231,"6216":230,"622":228,"622423222549":228,"62500":230,"627":228,"628":228,"62800":232,"63":[228,230,231],"632":228,"633":228,"6342730000":228,"639038":228,"63979":228,"63979000000":228,"63979249600":228,"64":[227,228,230],"640":[230,231],"641":230,"642964":230,"643245":228,"647":230,"64bit":227,"65":[228,230],"650":230,"6500":230,"6510":230,"6520":230,"6530":230,"6540":230,"6550":230,"6560":230,"6570":230,"6580":230,"659":228,"6590":230,"65\ucd08":230,"66":[228,230],"660":[228,230,231],"6666":228,"66797":228,"668":228,"67":[228,230,231],"6710":230,"672":228,"67375":230,"674649":230,"6765":228,"6770":230,"677226":228,"678903":230,"679886c13a31":230,"68":[228,230],"680":[230,231],"6809":230,"681":[228,230],"683":230,"68300":[230,231],"687":228,"688":228,"688585":228,"69":[228,230,232],"6905":228,"691":228,"69198":230,"692165":228,"69238":230,"69827":231,"6\uc790\ub9ac":[17,23,27,45,56],"6bfa":[28,232],"7":[17,29,67,219,226,228,230,231,232],"70":[228,230,231],"700":[230,231],"70010715700":230,"70010792700":230,"70011562700":230,"70011639700":230,"70011871000":230,"70012102000":230,"70032276000":230,"70033816000":230,"7037":230,"70700":230,"708":228,"7088":230,"71":[230,231],"71073":230,"71200":231,"713":228,"71300":231,"71600":230,"71831":230,"72":[228,230],"720":[230,231],"724854":228,"72500":230,"727":228,"72700":230,"73":230,"73100":[230,231],"732":[230,231],"73300":[230,231],"73400":231,"73551":230,"73700":231,"738":228,"73800":[230,231],"73900":231,"74":[230,231,232],"740":[230,231],"74000":[230,231],"742043":228,"74300":231,"7437050":228,"74400":231,"7450":230,"74600":231,"749":228,"74900":231,"7499":230,"75":[228,230,231],"750":230,"750761":228,"750787":228,"75200":230,"752808":228,"7544":231,"754517":228,"754859":230,"76":[230,231],"760":[230,231],"761":228,"76100":232,"76300":231,"76400":230,"765":228,"7650":230,"766":228,"76600":230,"767":228,"76900":230,"77":[230,231],"770":230,"77000":230,"770841":228,"77100":230,"77150":230,"7715780":230,"77221":230,"77222":230,"772625":228,"7726846":230,"77300":230,"775":[228,230],"77500":230,"77600":230,"777":228,"77700":230,"7780":[230,231,232],"77800":230,"77900":230,"78":230,"780":[230,231],"781":228,"78100":230,"781575":230,"78400":230,"784302":228,"784546":228,"784913":228,"785000":228,"78600":230,"787":230,"788000":228,"7884712":230,"7884732":230,"7884994":230,"7884997":230,"7885000":230,"7885001":230,"7885011":230,"7885012":230,"7890":230,"78900":230,"789000":228,"790":231,"7900":230,"790000":228,"7910":230,"791000":228,"7920":230,"792000":228,"793":228,"7930":230,"79300":230,"793000":228,"7940":230,"7950":[230,231],"79500":230,"795000":228,"796":[230,231],"79600":230,"796000":228,"797":230,"7970":230,"7971":230,"79800":[230,231],"799":228,"7990":230,"8":[17,125,131,134,151,152,171,224,227,228,230,231,232],"80":[230,231],"800":[230,231],"8000\uc77c":228,"800\uc6d0":228,"8010":[230,231],"8014526011":[230,231],"8019":230,"802":232,"8030":230,"80317":230,"803790":228,"8040":230,"805":230,"80500":230,"805084":228,"8086":230,"80976":230,"81":[17,45,152,230],"810":[230,231],"813":231,"8141":232,"8150":230,"8150870000":228,"819":230,"82":230,"820":[230,231],"8200":230,"822":[230,231],"8240":[230,231],"825":230,"8260":230,"828611":228,"83":230,"830":228,"8300":[230,231],"830264":230,"831":228,"835":228,"836":[228,230],"8370":230,"8390":[230,231],"84":230,"840":[230,231],"8400":[230,231],"84031":230,"8410":[230,231],"841983":228,"842":232,"8440":[230,231],"8450":[230,231],"848":230,"849":228,"84e17a5232d0":230,"85":[230,231],"850":230,"8500":[230,231],"851":230,"852":230,"852539":228,"853638":228,"85382":230,"855":230,"856":230,"8592":230,"85b07632":93,"86":[230,231],"860":230,"864":228,"8640":5,"86400":231,"8686":230,"868911":230,"869141":228,"87":[228,230],"8720":230,"878":230,"8785122":230,"88":[230,231],"880":230,"882":228,"8835":5,"88400":231,"885":230,"888":228,"888470000":228,"889":228,"89":[228,230,231,232],"893":228,"894":228,"897949":228,"898":230,"8\uc790\ub9ac":17,"9":[17,125,131,134,224,227,228,230],"900":230,"90000":231,"9001":[230,231],"900110":230,"900111":230,"900121":230,"900122":230,"900125":230,"900128":230,"900250":[230,231],"900280":[230,231],"900290":[230,231],"900310":[230,231],"900340":[230,231],"900390":230,"9004":[90,231],"900410":230,"900\uac1c":17,"900\uc6d0":228,"901":[228,230],"902":[228,230],"9020":[28,232],"903":230,"904":[228,230],"904000000":228,"904156000":228,"9048":230,"905":230,"905107":228,"9052":[230,231],"9055":231,"906":230,"907":[228,230],"90700":231,"908":[228,230],"909":230,"90\ucd08\ub300\uae30":30,"91":230,"910":[17,230],"910822":228,"911":230,"912":230,"913":230,"91300":231,"914":230,"91400":230,"915":[228,230],"916":230,"917":230,"917697":228,"918":230,"91800":230,"919":230,"92":230,"920":230,"9201":230,"9203":230,"9205":230,"921":230,"922":230,"923":230,"924":230,"93":[228,230,232],"930":[228,230],"9300":230,"931":230,"9313":228,"932":230,"933":230,"93302":230,"934141":228,"936":228,"938":230,"93800":230,"939":230,"94":230,"941":228,"941413":231,"945":[228,230],"946":230,"949":230,"95":[230,231],"950":230,"950130":[230,231],"950190":[230,231],"9508":5,"951":230,"95200":231,"952b31f8":93,"953":230,"955":[228,230],"955547":231,"9567":230,"957":230,"958":230,"959":230,"96":230,"96300":230,"969":230,"9694":93,"97":[228,230,231],"970":230,"9717":228,"972":228,"976":228,"977":228,"9787":230,"9788":230,"9789":230,"9790":[228,230],"9791":230,"9792":230,"9797":231,"9798":231,"9799":231,"98":230,"9800":231,"9801":231,"9802":231,"984":228,"985":228,"98600":230,"988":228,"9895":228,"99":[17,230],"990":230,"991":230,"991877":228,"991d":93,"992":230,"993":230,"9950":230,"99500":230,"9991":230,"99991231":17,"9\uac1c":17,"\uac00":[17,45,48,86,227,228,230,231,232],"\uac00\uaca9":[17,228,231],"\uac00\uaca9\ub370\uc774\ud130":228,"\uac00\uaca9\ub370\uc774\ud130\ub97c":228,"\uac00\uaca9\ub370\uc774\ud130\uc758":228,"\uac00\uaca9\ubcc0\ud654\uac00":228,"\uac00\uaca9\uc124\uc815":230,"\uac00\uaca9\uc73c\ub85c":17,"\uac00\uaca9\uc740":228,"\uac00\uaca9\uc744":228,"\uac00\uaca9\uc758":228,"\uac00\uaca9\uc774":228,"\uac00\uaca9\uc778\uac00":228,"\uac00\uaca9\uc815\ubcf4":228,"\uac00\uaca9\uc815\ubcf4\uac00":228,"\uac00\uacf5\ud558\uc5ec":[29,45,48],"\uac00\ub2a5":17,"\uac00\ub2a5\ubb38\uc758":231,"\uac00\ub2a5\uc885\ubaa9\uc694\uccad":231,"\uac00\ub2a5\ud558\uae30":230,"\uac00\ub2a5\ud558\ub2e4":[228,230],"\uac00\ub2a5\ud558\ub2e4\uba74":228,"\uac00\ub2a5\ud558\ub3c4\ub85d":[228,231],"\uac00\ub2a5\ud558\uba70":[30,231],"\uac00\ub2a5\ud558\uc9c0":228,"\uac00\ub2a5\ud55c":[22,29,45,48,228,230,231,232],"\uac00\ub2a5\ud569\ub2c8\ub2e4":[17,30,45,152,227,231,232],"\uac00\ub2a5\ud574\uc57c\uc9c0\ub9cc":[45,48],"\uac00\ub2a5\ud588\ub2e4":228,"\uac00\ub2a5\ud588\ub2e4\uba74":48,"\uac00\ub824\ubc84\ub9ac\ub294":228,"\uac00\uc0c1\ud658\uacbd\uc744":227,"\uac00\uc774\ub4dc":[30,232],"\uac00\uc774\ub4dc\ub77c\uc778\uc740":231,"\uac00\uc774\ub4dc\ud558\ub294":231,"\uac00\uc7a5":[227,228,231,232],"\uac00\uc815\ud558\uace0":[228,231],"\uac00\uc815\ud569\ub2c8\ub2e4":227,"\uac00\uc815\ud588\uc744\ub54c":[228,232],"\uac00\uc838\ub2e4":231,"\uac00\uc838\ub2e4\uac00":228,"\uac00\uc838\uc624\uace0":[228,230],"\uac00\uc838\uc624\ub294":[228,232],"\uac00\uc838\uc624\ub3c4\ub85d":228,"\uac00\uc838\uc628\ub2e4":17,"\uac00\uc838\uc62c":[17,228],"\uac00\uc838\uc640":[228,230],"\uac00\uc9c0":231,"\uac00\uc9c0\uace0":[228,231],"\uac00\uc9c0\ub294":230,"\uac00\uc9c4":17,"\uac00\uce58\ub97c":231,"\uac01":[17,23,227,228,230,231,232],"\uac01\uac01":[45,48,227],"\uac01\uac01\uc758":230,"\uac01\uae30":228,"\uac01\uc885":[228,232],"\uac04\ub2e4":228,"\uac04\ub2e8\ud558\uac8c":[228,232],"\uac04\ub2e8\ud55c":231,"\uac04\uc758":231,"\uac04\uc811\uc801\uc73c\ub85c":[230,231],"\uac10\ub9ac":17,"\uac10\ub9ac\uad6c\ubd84":17,"\uac10\ub9ac\uad6c\ubd84\uc744":[17,29],"\uac10\ub9ac\uad6c\ubd84\uc774":29,"\uac10\ub9ac\uc885\ubaa9":[17,29],"\uac10\ub9c8":[230,231],"\uac10\uc218\ud574\uc57c":228,"\uac10\uc2dc\uc2dc\uc791":231,"\uac12":[17,29,230,231],"\uac12\ub4e4\uc744":[17,231],"\uac12\ub9cc":232,"\uac12\uc73c\ub85c":[17,227],"\uac12\uc740":[17,29,227],"\uac12\uc744":[17,23,29,228],"\uac12\uc758":228,"\uac12\uc774":[17,23,29,230],"\uac12\uc785\ub2c8\ub2e4":227,"\uac15\ub825\ud55c":228,"\uac15\uc81c\ud558\uc9c0\ub9cc":227,"\uac19\ub2e4":228,"\uac19\uc2b5\ub2c8\ub2e4":[17,231,232],"\uac19\uc544\uc11c":228,"\uac19\uc558\ub2e4":228,"\uac19\uc740":[17,23,228,230,231,232],"\uac19\uc740\ub370":228,"\uac19\uc744":232,"\uac19\uc774":[45,228,230,231,232],"\uac19\uc9c0":227,"\uac19\uc9c0\ub294":228,"\uac1c\ubc1c":[227,231,232],"\uac1c\ubc1c\uacfc\uc815\uc5d0\uc11c\uc758":228,"\uac1c\ubc1c\ub418\uc5c8\uc2b5\ub2c8\ub2e4":231,"\uac1c\ubc1c\uc744":[228,231],"\uac1c\ubc1c\uc774":[228,231],"\uac1c\ubc1c\uc790\uac00":231,"\uac1c\ubc1c\uc790\ub294":231,"\uac1c\ubc1c\ud558\uac8c":228,"\uac1c\ubc1c\ud558\ub294":231,"\uac1c\ubc1c\ud560":228,"\uac1c\ubc1c\ud574":231,"\uac1c\ubc1c\ud574\ubd24\ub294\ub370":228,"\uac1c\ubcc4":45,"\uac1c\ubcc4\uc885\ubaa9":228,"\uac1c\ubcc4\uc885\ubaa9\uc758":228,"\uac1c\uc218":23,"\uac1c\uc218\ub97c":[17,29],"\uac1c\uc218\uc5d0\ub294":228,"\uac1c\uc218\uc758":228,"\uac1c\uc758":17,"\uac1c\uc778\ubc29\ud654\ubcbd":22,"\uac1c\uc778\uc801\uc73c\ub85c":[227,228],"\uac1c\uc778\uc801\uc73c\ub85c\ub294":[228,231],"\uac1d\uccb4":230,"\uac1d\uccb4\ub294":230,"\uac1d\uccb4\ub85c":232,"\uac1d\uccb4\ub97c":[28,29,45,232],"\uac1d\uccb4\uc5d0":29,"\uac1d\uccb4\uc5d0\uc11c":29,"\uac1d\uccb4\uc758":[230,231],"\uac1d\uccb4\uc778\ub370":230,"\uac2f\uc218":17,"\uac31\uc2e0\ud558\uace0":230,"\uac31\uc2e0\ud558\ub294":228,"\uac31\uc2e0\ud560":228,"\uac70\uae30\uc11c\ubd80\ud130":228,"\uac70\ub798":[17,45,228],"\uac70\ub798\uad6c\ubd84":[17,45,152,230,231],"\uac70\ub798\ub300\uae08":[228,230,231],"\uac70\ub798\ub300\uae08\uc99d\uac10":[230,231],"\uac70\ub798\ub300\ube44":[230,231,232],"\uac70\ub798\ub7c9":[228,230,231,232],"\uac70\ub798\ub7c9\uc804\uc77c\ub300\ube44":[230,231],"\uac70\ub798\ube44\uc6a9":[230,231],"\uac70\ub798\uc18c":[3,17,231],"\uac70\ub798\uc18c\ub85c":17,"\uac70\ub798\uc18c\uc5d0\uc11c":228,"\uac70\ub798\uc18c\uc758":228,"\uac70\ub798\uc815\uc9c0":[17,29],"\uac70\ub798\ud558\ub294":228,"\uac70\ub798\ud558\ub294\uac8c":228,"\uac70\ub798\ud68c\uc804\uc728":[230,231],"\uac70\ub9ac\uac00":231,"\uac70\ubd80\ub418\uc5c8\uc2b5\ub2c8\ub2e4":23,"\uac70\uc758":228,"\uac70\uccd0":[228,230],"\uac70\uccd0\ub3c4":228,"\uac70\uce5c":231,"\uac71\uc815\ud560":228,"\uac74":231,"\uac78":231,"\uac78\uace0":29,"\uac78\ub85c":228,"\uac78\ub9bc\ubaa9\uc774\ub2e4":228,"\uac78\uc9c0\ub3c4":228,"\uac80\uc0c9":[17,230],"\uac80\uc0c9\uacb0\uacfc\ub294":45,"\uac80\uc0c9\ub41c":45,"\uac80\uc0c9\uc2dc":29,"\uac80\uc0c9\ucc3d\uc5d0":227,"\uac80\uc0c9\ud558\ub294":227,"\uac80\uc740\uc0c9":227,"\uac80\ud1a0\ud574\ubcf8":228,"\uac81\ub2c8\ub2e4":227,"\uac83":[17,228],"\uac83\uacfc":[227,228],"\uac83\uacfc\ub294":231,"\uac83\ub3c4":231,"\uac83\ub4e4\uc774":232,"\uac83\ub4e4\uc774\ub2e4":230,"\uac83\ub9cc":48,"\uac83\uc5d0":[228,231],"\uac83\uc73c\ub85c":[17,227,228,232],"\uac83\uc740":[228,230],"\uac83\uc744":[227,228,232],"\uac83\uc774":[228,230,231,232],"\uac83\uc774\ub2e4":228,"\uac83\uc774\ubbc0\ub85c":17,"\uac83\uc778\ub370\uc694":231,"\uac83\uc778\uc9c0\ub294":228,"\uac83\uc778\uc9c0\ub97c":17,"\uac83\uc785\ub2c8\ub2e4":232,"\uac83\ucc98\ub7fc":231,"\uac8c":[231,232],"\uacac\uc801\ub3c4":228,"\uacb0\uacfc":[17,228,230,231,232],"\uacb0\uacfc\uac00":[30,228,231],"\uacb0\uacfc\uac12\uc774":17,"\uacb0\uacfc\ub294":[228,230],"\uacb0\uacfc\ub4e4\uc744":231,"\uacb0\uacfc\ub97c":[228,230,231],"\uacb0\uacfc\ubb3c\ub9cc":[230,232],"\uacb0\uacfc\uc5d0\uc11c":228,"\uacb0\uacfc\uc640":228,"\uacb0\uacfc\uc774\ub2e4":228,"\uacb0\uad6d":228,"\uacb0\uad6d\uc740":230,"\uacb0\ub860":228,"\uacb0\ub860\uc801\uc73c\ub85c":231,"\uacb0\ub860\uc801\uc73c\ub85c\ub294":[228,231],"\uacb0\uc0b0\uc6d4":[230,231,232],"\uacb9\uccd0\uc9c0\ub294":228,"\uacb9\uce58\uac8c":228,"\uacb9\uce58\ub294":228,"\uacbd\uace0":[17,86],"\uacbd\uace0\uac00":227,"\uacbd\ub85c":17,"\uacbd\ub85c\ub97c":[17,29],"\uacbd\ub85c\uc5d0":[29,228],"\uacbd\ub85c\uc758":231,"\uacbd\ubc29":231,"\uacbd\uc6b0":[17,29,30,45,48,227,228,230,231,232],"\uacbd\uc6b0\uac00":[228,231],"\uacbd\uc6b0\ub294":[228,232],"\uacbd\uc6b0\ub3c4":[228,231],"\uacbd\uc6b0\ub77c\uba74":[227,230],"\uacbd\uc6b0\ub97c":231,"\uacbd\uc6b0\ub9cc":[230,231],"\uacbd\uc6b0\uc5d0":[45,48,227,228,230,232],"\uacbd\uc6b0\uc5d0\ub294":[17,227,230,231,232],"\uacbd\uc6b0\uc5d0\ub3c4":17,"\uacbd\uc6b0\uc5d0\ub9cc":228,"\uacbd\uc6b0\uc758":228,"\uacbd\ud5d8\uc744":228,"\uacc4\uc0b0\uc2dc":228,"\uacc4\uc0b0\uc744":228,"\uacc4\uc0b0\ud558\ub294":228,"\uacc4\uc0b0\ud558\ub294\uc9c0\ub294":228,"\uacc4\uc0b0\ud574\ubcf4\uba74":228,"\uacc4\uc0b0\ud574\uc11c":228,"\uacc4\uc18d":[17,48,231],"\uacc4\uc18d\ud574\uc11c":230,"\uacc4\uc815":[227,232],"\uacc4\uc88c":[17,22,29,232],"\uacc4\uc88c\uac1c\uc124":227,"\uacc4\uc88c\ub97c":86,"\uacc4\uc88c\ubbf8\uacb0\uc81c\uccad\uc0b0\uac00\ub2a5\uc218\ub7c9\uc870\ud68c\uc694\uccad":231,"\uacc4\uc88c\ubc88\ud638":[17,45,230,231,232],"\uacc4\uc88c\ubc88\ud638\ub85c":[230,231],"\uacc4\uc88c\ubc88\ud638\ub97c":[29,232],"\uacc4\uc88c\ubcc4":45,"\uacc4\uc88c\ube44\ubc00\ubc88\ud638\ub97c":86,"\uacc4\uc88c\uc5d0":232,"\uacc4\uc88c\uc758":[45,232],"\uacc4\uc88c\uc815\ubcf4\uc5c6\uc74c":22,"\uace0\uac00":[228,230,231,232],"\uace0\uac1d":232,"\uace0\uac1did":232,"\uace0\ub824\ub418\ub294":228,"\uace0\ub824\ud558\uc9c4":231,"\uace0\ub824\ud574\uc11c":231,"\uace0\ub824\ud588\ub358":228,"\uace0\ub974\uc790\uba74":228,"\uace0\ub97c":228,"\uace0\ubbfc\ud558\uac8c":228,"\uace0\ubbfc\ud558\ub2e4\uac00":228,"\uace0\ubbfc\ud558\uc600\uace0":231,"\uace0\ubbfc\ud574":231,"\uace0\ubbfc\ud588\uace0":231,"\uace0\uc720\ubc88\ud638\uc640":17,"\uace0\uc720\ubc88\ud638\uc758":17,"\uace0\uc9d1\ud558\uc9c0":[230,231],"\uace8\ub4e0\uc13c\uce04\ub9ac":230,"\uace8\ub77c\uc11c":228,"\uacf1\ud574\uc11c":17,"\uacf3\uc5d0\uc11c":[17,228],"\uacf3\uc73c\ub85c":231,"\uacf5\ubc31":[17,45],"\uacf5\ubc31\uc73c\ub85c":17,"\uacf5\ubc31\uc774":228,"\uacf5\uc2dd\uc801\uc778":228,"\uacf5\uc720\ud568\uc73c\ub85c\uc368":228,"\uacfc":[45,228],"\uacfc\uac70":228,"\uacfc\uac70\uae30\uac04":228,"\uacfc\uac70\uc5d0":228,"\uacfc\uac70\uc758":228,"\uacfc\ub3c4\ud55c":[17,228],"\uacfc\ubd80\ud558":22,"\uacfc\uc5f0":228,"\uacfc\uc758":48,"\uacfc\uc815\uae4c\uc9c0\ub97c":231,"\uacfc\uc815\uc5d0":227,"\uacfc\uc815\uc5d0\uc11c":[45,48,227,232],"\uacfc\uc815\uc744":230,"\uad00\uacc4\ub97c":231,"\uad00\ub828":[23,29,30,45,48,227,228,232],"\uad00\ub828\ub41c":[29,45,48,228,230,231,232],"\uad00\ub828\ud558\uc5ec":231,"\uad00\ub828\ud574":48,"\uad00\ub828\ud574\uc11c":[228,231,232],"\uad00\ub828\ud574\uc11c\ub294":[228,230,231],"\uad00\ub9ac":[231,232],"\uad00\ub9ac\ub418\uba70":232,"\uad00\ub9ac\ub97c":232,"\uad00\ub9ac\uc0ac\ubc88":230,"\uad00\ub9ac\uc5d0":228,"\uad00\ub9ac\uc790":[227,230,232],"\uad00\ub9ac\uc885\ubaa9":[17,29],"\uad00\ub9ac\ud558\uace0":228,"\uad00\ub9ac\ud558\ub294":228,"\uad00\uc2ec\uc885\ubaa9":[45,48],"\uad00\uc2ec\uc885\ubaa9\uacfc\ub294":17,"\uad00\uc2ec\uc885\ubaa9\uc815\ubcf4\uc694\uccad":230,"\uad00\uc2ec\uc885\ubaa9\uc870\ud68c\uc640":30,"\uad00\uc810\uc5d0\uc11c\ub294":228,"\uad00\ud574\uc11c\ub294":228,"\uad04\ud638\ub85c":227,"\uad11\uc8fc\uc2e0\uc138\uacc4":230,"\uad50\uccb4\ud569\ub2c8\ub2e4":227,"\uad50\ud1b5\uc815\ub9ac":231,"\uad50\ud1b5\uc815\ub9ac\ubd80\ud130":231,"\uad50\ud658":22,"\uad6c\uac04\uc5d0":232,"\uad6c\uac04\uc774":228,"\uad6c\ub3c5":231,"\uad6c\ub3d9\ub418\ub294":232,"\uad6c\ub3d9\ub418\uba70":232,"\uad6c\ub3d9\ud558\uae30":231,"\uad6c\ub9ac":231,"\uad6c\ub9e4\ud558\ub294\uac8c":228,"\uad6c\ub9e4\ud558\uba74":228,"\uad6c\ub9e4\ud55c\ub2e4":228,"\uad6c\ubb38\uc774":227,"\uad6c\ubcc4\ub418\ub294":228,"\uad6c\ubd84":[17,23,45],"\uad6c\ubd84\uac00\ub2a5\ud55c":[230,231],"\uad6c\ubd84\uac12":17,"\uad6c\ubd84\uac12\uc744":29,"\uad6c\ubd84\ub418\uba70":17,"\uad6c\ubd84\ub418\uc11c":23,"\uad6c\ubd84\ub429\ub2c8\ub2e4":17,"\uad6c\ubd84\uba85":[17,23,27,56,230,231],"\uad6c\ubd84\uc5c6\uc74c":3,"\uad6c\ubd84\uc740":17,"\uad6c\ubd84\uc744":17,"\uad6c\ubd84\uc790":[17,23],"\uad6c\ubd84\uc790\ub294":17,"\uad6c\ubd84\uc790\ub85c":17,"\uad6c\ubd84\ud55c\ub2e4":23,"\uad6c\ubd84\ud574":228,"\uad6c\ubd84\ud574\uc11c":17,"\uad6c\uc131\ub418\uc5b4":232,"\uad6c\uc131\ubd80\ud130":227,"\uad6c\uc131\uc744":231,"\uad6c\uc131\uc774":228,"\uad6c\uc131\ud569\ub2c8\ub2e4":[227,231],"\uad6c\uc785":228,"\uad6c\uc785\uc5d0":228,"\uad6c\uc870":231,"\uad6c\uc870\uac00":[228,231],"\uad6c\uc870\ub294":232,"\uad6c\uc870\uc5d0\uc11c":232,"\uad6c\uc870\uc785\ub2c8\ub2e4":232,"\uad6c\uc870\uccb4":17,"\uad6c\uccb4\uc801\uc73c\ub85c":[228,230,231],"\uad6c\uccb4\uc801\uc778":[228,231],"\uad6c\ucd95\ud558\uace0\uc790":231,"\uad6c\ud558\uae30":17,"\uad6c\ud558\ub294":[17,227],"\uad6c\ud55c\ub2e4":17,"\uad6c\ud604":[45,231],"\uad6c\ud604\uacfc":232,"\uad6c\ud604\ub418\uc5b4":[29,45],"\uad6c\ud604\ub418\uc5b4\uc788\uc2b5\ub2c8\ub2e4":232,"\uad6c\ud604\ub41c":[228,231,232],"\uad6c\ud604\ub4e4\uae4c\uc9c0":45,"\uad6c\ud604\uc774":[28,29,232],"\uad6c\ud604\uccb4":48,"\uad6c\ud604\ud558\uace0":230,"\uad6c\ud604\ud558\ub294":228,"\uad6c\ud604\ud569\ub2c8\ub2e4":45,"\uad6c\ud604\ud574":[228,231],"\uad6c\ud604\ud574\ub193\uc73c\uc2e0":228,"\uad6c\ud604\ud574\ub193\uc740":232,"\uad6c\ud604\ud574\ub193\uc740\uac8c":228,"\uad6c\ud604\ud574\ubcf4\ub294\uac74":228,"\uad6c\ud604\ud574\uc57c\ud558\uba70":48,"\uad6c\ud604\ud574\uc8fc\uc2e0":228,"\uad6c\ud604\ud6c4":232,"\uad6d\ub0b4":228,"\uad6d\ub0b4\uc8fc\uc2dd":[17,23],"\uad73\uc774":[227,231,232],"\uad8c\uc7a5\ud558\uc9c4":227,"\uad8c\uc7a5\ud569\ub2c8\ub2e4":227,"\uad8c\ud558\uace0":228,"\uad8c\ud55c\uc73c\ub85c":232,"\uad8c\ud55c\uc774":[227,230],"\uadf8":[17,48,228,231,232],"\uadf8\uac83\uc744":231,"\uadf8\uac8c":228,"\uadf8\ub0e5":[227,228],"\uadf8\ub300\ub85c":[228,230,231],"\uadf8\ub300\ub85c\uc758":228,"\uadf8\ub4e4":231,"\uadf8\ub7ec\uace0":228,"\uadf8\ub7ec\uba74":227,"\uadf8\ub7ec\uba74\uc11c":228,"\uadf8\ub7ec\ud55c":230,"\uadf8\ub7f0":232,"\uadf8\ub807\uac8c":228,"\uadf8\ub807\uae30":228,"\uadf8\ub807\ub2e4\uace0":227,"\uadf8\ub807\uc9c0":[17,29,45,48,230],"\uadf8\ub85c":231,"\uadf8\ub8f9\uc744":29,"\uadf8\ub9ac":228,"\uadf8\ub9ac\uace0":[17,228,231,232],"\uadf8\ubcf4\ub2e4":[228,231],"\uadf8\uc5d0":[228,231],"\uadf8\uc640":[45,48],"\uae00\uc744":227,"\uae08\uc120\ubb3c":17,"\uae08\uc735":228,"\uae08\uc735\uc5c5":17,"\uae08\uc735\uc758":228,"\uae08\ud638\uc11d\uc720":230,"\uae08\ud654\ud53c\uc5d0\uc2a4\uc2dc":230,"\uae09\uaca9\ud558\uac8c":231,"\uae09\uaca9\ud55c":228,"\uae0d\uc815\uc801\uc778":228,"\uae30":[45,48],"\uae30\uac04":228,"\uae30\uac04\ub3c4":228,"\uae30\uac04\uc5d0":228,"\uae30\uac04\uc744":228,"\uae30\uac04\uc758":228,"\uae30\ub2a5":[17,29,45,48,228],"\uae30\ub2a5\ub4e4\uacfc":231,"\uae30\ub2a5\ub4e4\ub85c\ub294":228,"\uae30\ub2a5\ub4e4\uc5d0":231,"\uae30\ub2a5\ub4e4\uc740":230,"\uae30\ub2a5\ub4e4\uc744":[17,29,228,232],"\uae30\ub2a5\ub4e4\uc774":231,"\uae30\ub2a5\ub9cc":231,"\uae30\ub2a5\uc5d0":[45,48],"\uae30\ub2a5\uc740":[228,231],"\uae30\ub2a5\uc744":[17,227,231,232],"\uae30\ub2a5\uc774":17,"\uae30\ub2a5\uc774\ub984":17,"\uae30\ub300\ud558\ub294":231,"\uae30\ub300\ud560":228,"\uae30\ubc18":[227,228,231,232],"\uae30\ubc18\uc73c\ub85c":[228,231,232],"\uae30\ubc18\uc774":231,"\uae30\ubc18\ud55c":231,"\uae30\ubc18\ud574":228,"\uae30\ubcf8":[17,45,227,228,230,232],"\uae30\ubcf8\uac12":[17,231],"\uae30\ubcf8\uac12\uc73c\ub85c":231,"\uae30\ubcf8\uac12\uc740":228,"\uae30\ubcf8\uc635\uc158":228,"\uae30\ubcf8\uc73c\ub85c":230,"\uae30\ubcf8\uc801\uc73c\ub85c":[45,48,228,230,232],"\uae30\ubcf8\uc801\uc778":[228,231],"\uae30\ubcf8\uc815\ubcf4\ub4e4\ub3c4":230,"\uae30\ubcf8\uc815\ubcf4\ub4e4\uc744":230,"\uae30\ubcf8\uc815\ubcf4\ub97c":45,"\uae30\uc5b4\ub9c1":230,"\uae30\uc5b5\ud55c\ub2e4":228,"\uae30\uc5c5\ubd84\ud560\uc744":228,"\uae30\uc810\uc73c\ub85c":228,"\uae30\uc874":[17,23,227,228,230,231],"\uae30\uc874\uc5d0":[17,227,228,230],"\uae30\uc874\uc758":[29,48,230],"\uae30\uc874\ucc98\ub7fc":17,"\uae30\uc900":228,"\uae30\uc900\uac00":[230,231,232],"\uae30\uc900\uac00\uac00":228,"\uae30\uc900\uac00\ub97c":[17,228],"\uae30\uc900\uac00\ubcc0\uacbd":231,"\uae30\uc900\uac00\uc640":228,"\uae30\uc900\uc73c\ub85c":[17,227,228,231],"\uae30\uc900\uc774\ub098":228,"\uae30\uc900\uc77c\uc790":231,"\uae30\ucd08\uc790\uc0b0\ucf54\ub4dc":17,"\uae30\ucd08\uc790\uc0b0\ucf54\ub4dc\uad6c\ubd84":17,"\uae30\ud68c\uac00":228,"\uae34":228,"\uae38\uac8c":228,"\uae38\ub2e4":228,"\uae38\uc5b4\uc9c8":230,"\uae38\uc5b4\uc9c8\ub4ef\ud574":228,"\uae4c\uc9c0":[48,227],"\uae4c\uc9c0\ub9cc":17,"\uaf2d":17,"\uaf34\ub85c":228,"\uaf64\ub098":228,"\ub04a\uace0":228,"\ub054":231,"\ub098\uac00\ub294":228,"\ub098\uac00\ub358":231,"\ub098\ub220\ubcf4\uba74":228,"\ub098\ub258\uc5b4\uc11c":228,"\ub098\ub258\uc5b4\uc838":17,"\ub098\ub294":228,"\ub098\ub984\ub300\ub85c\uc758":228,"\ub098\ub984\uc758":231,"\ub098\uba38\uc9c0":[17,23,228],"\ub098\uba38\uc9c0\ub294":17,"\ub098\uc058\uba74":228,"\ub098\uc11c":227,"\ub098\uc544\uac00\uc11c\ub294":231,"\ub098\uc624\ub294":[228,230],"\ub098\uc635\ub2c8\ub2e4":232,"\ub098\uc640":228,"\ub098\uc654\uc9c0\ub9cc":227,"\ub098\uc740":231,"\ub098\uc774\ube0c\ud558\uac8c":228,"\ub098\uc911\uc5d0":228,"\ub09c\uad00\uc5d0":228,"\ub09c\uad00\uc73c\ub85c":228,"\ub0a0\uc9dc":228,"\ub0a0\uc9dc\uac00":228,"\ub0a0\uc9dc\ub97c":228,"\ub0a0\uc9dc\uc758":231,"\ub0b4":[17,228,231],"\ub0b4\uac00":228,"\ub0b4\ub9b4":228,"\ub0b4\ubd80":228,"\ub0b4\ubd80\uc5d0\uc11c":[45,48,232],"\ub0b4\ubd80\uc5d0\uc11c\ub9cc":230,"\ub0b4\ubd80\uc801\uc73c\ub85c":[45,48,228,230,231,232],"\ub0b4\ubd80\uc801\uc73c\ub85c\ub294":[228,231],"\ub0b4\uc5b4\ubd24\ub294\ub370":228,"\ub0b4\uc5d0\uc11c":[29,48,230,231],"\ub0b4\uc5ed":45,"\ub0b4\uc5ed\uc744":45,"\ub0b4\uc5ed\uc774":23,"\ub0b4\uc6a9":[4,230],"\ub0b4\uc6a9\uacfc":227,"\ub0b4\uc6a9\ub3c4":232,"\ub0b4\uc6a9\ub4e4\uc744":[231,232],"\ub0b4\uc6a9\uc5d0":232,"\ub0b4\uc6a9\uc740":231,"\ub0b4\uc6a9\uc744":[45,48,227,232],"\ub0b4\uc6a9\uc774":231,"\ub0b4\uc6a9\uc785\ub2c8\ub2e4":227,"\ub0b4\uc6a9\uc911":228,"\ub0b4\uc6a9\uc911\uc5d0":228,"\ub0b4\uc7ac\ubcc0\ub3d9\uc131":[230,231],"\ub0b4\uc870\uac74\uc2dd1":17,"\ub0b4\uc870\uac74\uc2dd2":17,"\ub0b4\uc870\uac74\uc2dd3":17,"\ub0b4\uc870\uac74\uc2dd\uc218\uc815":231,"\ub108\ubb34":[228,230],"\ub113\uac8c\ub294":29,"\ub118\uac8c":30,"\ub118\uc5b4\uc11c":228,"\ub118\uc5b4\uc624\ub294":[230,231],"\ub123\uac70\ub098":231,"\ub123\uace0":231,"\ub123\ub294":231,"\ub123\uc5b4\uc918\uc57c":[230,231],"\ub124\uc624\uc704\uc988":230,"\ub124\uc624\uc704\uc988\ud640\ub529\uc2a4":230,"\ub124\uc774\ubc84":228,"\ub124\uc774\ubc84\ub294":228,"\ub124\uc774\ubc84\uc5d0\uc11c":228,"\ub124\uc774\ubc84\uc640":228,"\ub124\uc774\ubc84\uce21\uc758":228,"\ub144":45,"\ub178\ucd9c\ub418\ub294":230,"\ub178\ud2b8\ubd81":[230,231],"\ub180\ub78d\uac8c\ub3c4":228,"\ub193\uc558\ub354\ub77c\ub3c4":231,"\ub204\uad6c\ub098":228,"\ub204\ub77d":86,"\ub204\ub77d\ub41c":228,"\ub204\ub974\ub77c\ub294":232,"\ub204\ub974\uc2dc\uba74":232,"\ub204\ub985\ub2c8\ub2e4":232,"\ub204\uc801\uac70\ub798\ub300\uae08":[230,231],"\ub204\uc801\uac70\ub798\ub7c9":[230,231],"\ub274\uc2a4":231,"\ub290\ub08c\ub3c4":228,"\ub290\uc2a8\ud558\uac8c":228,"\ub294":[17,45,48,228,231,232],"\ub2a5\ub825\uc790":228,"\ub2a5\ub825\uc790\ub4e4\uc774":228,"\ub2e4":[228,231],"\ub2e4\ub8e8\uae30\ubcf4\ub2e4\ub294":231,"\ub2e4\ub8e8\ub2e4":228,"\ub2e4\ub8e8\uc9c0":232,"\ub2e4\ub8f8\uc73c\ub85c\uc368":231,"\ub2e4\ub8f9\ub2c8\ub2e4":227,"\ub2e4\ub974\uac8c":[48,228],"\ub2e4\ub978":[17,29,228,230,231,232],"\ub2e4\ub97c":228,"\ub2e4\ub985\ub2c8\ub2e4":17,"\ub2e4\ub9cc":[45,48,228,230,231],"\ub2e4\uc218\uc758":17,"\ub2e4\uc2dc":[17,23,48,227,228,230,232],"\ub2e4\uc591\ud55c":228,"\ub2e4\uc6b4\ub85c\ub354":228,"\ub2e4\uc6b4\ub85c\ub4dc":[227,228],"\ub2e4\uc6b4\ub85c\ub4dc\ub3c4":228,"\ub2e4\uc6b4\ub85c\ub4dc\ub97c":228,"\ub2e4\uc74c":[48,228],"\ub2e4\uc74c\uacfc":[23,228,232],"\ub2e4\uc74c\ubd80\ud130\ub294":227,"\ub2e4\uc74c\uc5d0\uc11c":228,"\ub2e4\uc74c\uc5d0\uc11c\ub294":228,"\ub2e4\uc74c\uc73c\ub85c":[228,231],"\ub2e4\uc74c\ucc98\ub7fc":232,"\ub2e4\uc911":231,"\ub2e4\ud589\uc774\ub2e4":228,"\ub2e8":17,"\ub2e8\uacc4":231,"\ub2e8\uacc4\ub85c":228,"\ub2e8\uacc4\ub97c":232,"\ub2e8\uacc4\ubd80\ud130":232,"\ub2e8\uacc4\uc5d0\uc11c":[231,232],"\ub2e8\uacc4\uc5d0\uc11c\ub294":227,"\ub2e8\uacc4\uc774\uae30":231,"\ub2e8\uacc4\uc801\uc73c\ub85c":232,"\ub2e8\uae30\uacfc\uc5f4":[17,29],"\ub2e8\uc21c":[17,228,232],"\ub2e8\uc21c\ud558\uac8c":228,"\ub2e8\uc21c\ud558\uac8c\ub294":231,"\ub2e8\uc21c\ud558\uba74\uc11c\ub3c4":29,"\ub2e8\uc21c\ud55c":[45,48,231],"\ub2e8\uc21c\ud788":232,"\ub2e8\uc704":[45,228],"\ub2e8\uc704\ub85c":[17,29],"\ub2e8\uc704\ubcf4\ub2e4":228,"\ub2e8\uc704\uccb4\uacb0\uac00":230,"\ub2e8\uc704\uccb4\uacb0\ub7c9":230,"\ub2e8\uc77c":[48,228],"\ub2e8\uc77c\uac00":17,"\ub2e8\uc808\uc2dc\ud0a4\ub294":17,"\ub2e8\uc810\uc774":228,"\ub2eb\uc2b5\ub2c8\ub2e4":232,"\ub2eb\uc740":232,"\ub2ec\ub77c\uc838\uc57c":17,"\ub2ec\ub77c\uc9c8":227,"\ub2ec\ub7ec\uc120\ubb3c":17,"\ub2ec\ub7ec\ucf5c\uc635\uc158":17,"\ub2ec\ub7ec\ud48b\uc635\uc158":17,"\ub2f4\ubcf4\ub300\ucd9c":[17,29],"\ub2f4\ubcf4\ub300\ucd9c\uc218\ub7c9":230,"\ub2f9\uae30\uc21c\uc774\uc775":[230,231,232],"\ub2f9\uc2dc\uc758":228,"\ub2f9\uc5f0\ud558\uac8c\ub3c4":228,"\ub2f9\uc77c":[17,228],"\ub2f9\uc77c\ub9e4\ub9e4\uc138\uae08":230,"\ub2f9\uc77c\ub9e4\ub9e4\uc218\uc218\ub8cc":230,"\ub2f9\uc77c\uc21c\ub9e4\uc218\ub7c9":230,"\ub2f9\uc77c\uc758":228,"\ub2f9\uc77c\ucd1d\ub9e4\ub3c4\uc190\uc775":230,"\ub2f9\uc7a5":[228,232],"\ub2f9\uc7a5\uc740":[227,228],"\ub2f9\ud574\uc904":228,"\ub300\uae30":30,"\ub300\uae30\uc2dc\uac04\uc774":[45,48],"\ub300\uae30\ud558\uc5ec":17,"\ub300\uae30\ud560":45,"\ub300\uae30\ud569\ub2c8\ub2e4":48,"\ub300\ub7b5":[227,228,230],"\ub300\ub7b5\uc801\uc778":232,"\ub300\ub7c9\uc758":228,"\ub300\ubd80\ubd84":231,"\ub300\ubd80\ubd84\uc758":232,"\ub300\ubd84\ub958":17,"\ub300\ube44\uae30\ud638":[230,231,232],"\ub300\uc0c1":29,"\ub300\uc0c1\uc120\ud0dd":228,"\ub300\uc0c1\uc5d0\uac8c\ub85c":231,"\ub300\uc2e0":[17,45,48,228,230,231],"\ub300\uc2e0\uc5d0":[228,230,231],"\ub300\uc2e0\uc99d\uad8c":228,"\ub300\uc2e0\uc99d\uad8c\uc5d0\uc11c\ub294":228,"\ub300\uc2e0\uc99d\uad8c\uc758":228,"\ub300\uc5c5\uc885\uad6c\ubd84":[228,230,231],"\ub300\uc6a9\uac00":[230,231,232],"\ub300\uc751\uc774":231,"\ub300\uc751\ud55c\uac8c":228,"\ub300\uc751\ud560":231,"\ub300\uc751\ud574":231,"\ub300\uc8fc\uac00\ub2a5\uc218\ub7c9":231,"\ub300\uc8fc\uac70\ub798\ub294":17,"\ub300\uccb4\ub420":227,"\ub300\uccb4\ud558\uc154\ub3c4":227,"\ub300\ucd9c\uc77c":[17,230],"\ub300\ucd9c\uc77c\uc740":17,"\ub300\ucd9c\uc77c\uc744":17,"\ub300\ud45c\uc801\uc73c\ub85c":231,"\ub300\ud55c":[17,23,30,45,48,228,230,232],"\ub300\ud55c\uc720\ud654":230,"\ub300\ud574":[5,29,45,48,227,228,231],"\ub300\ud574\uc11c":[227,230,231,232],"\ub300\ud574\uc11c\ub294":[227,228,230,231],"\ub300\ud574\uc11c\ub3c4":227,"\ub300\ud615":[230,231],"\ub354":[17,23,45,48,227,228,231,232],"\ub354\ube14\uc720\uac8c\uc784\uc988":230,"\ub354\uc6b1":228,"\ub354\uc774\uc0c1":[45,48,228,230],"\ub367\ubd99\uc5ec":228,"\ub367\ubd99\uc5ec\uc11c":231,"\ub367\ubd99\uc774\ub294":228,"\ub370\uc5d0":[227,231],"\ub370\uc774\ud0c0\ud45c":228,"\ub370\uc774\ud130":[5,17,22,23,29,45,48,228,230,232],"\ub370\uc774\ud130\uac00":[17,23,45,48,228,230],"\ub370\uc774\ud130\uac2f\uc218\ub97c":17,"\ub370\uc774\ud130\uae4c\uc9c0":228,"\ub370\uc774\ud130\ub294":[17,23,45,228],"\ub370\uc774\ud130\ub3c4":[23,228],"\ub370\uc774\ud130\ub4e4\uacfc":228,"\ub370\uc774\ud130\ub4e4\ub3c4":228,"\ub370\uc774\ud130\ub4e4\uc740":228,"\ub370\uc774\ud130\ub85c\ubd80\ud130":228,"\ub370\uc774\ud130\ub97c":[17,23,29,45,48,228,230,231],"\ub370\uc774\ud130\ub9cc":228,"\ub370\uc774\ud130\ubcc4":231,"\ub370\uc774\ud130\uc0c1\uc73c\ub85c":228,"\ub370\uc774\ud130\uc14b\uc2e4\uc2dc\uac04":231,"\ub370\uc774\ud130\uc218\uc2e0":22,"\ub370\uc774\ud130\uc5d0":[45,48,228],"\ub370\uc774\ud130\uc5d0\uc11c":[228,230],"\ub370\uc774\ud130\uc5d0\uc11c\ub294":228,"\ub370\uc774\ud130\uc640":228,"\ub370\uc774\ud130\uc640\ub3c4":228,"\ub370\uc774\ud130\uc758":228,"\ub370\uc774\ud130\uc774\ub2e4":228,"\ub370\uc774\ud130\uc804\ubb38":23,"\ub378\ud0c0":[230,231],"\ub3c4\uc6c0\ub9d0\uc744":227,"\ub3c4\uc6c0\uc774":[228,232],"\ub3c4\uc800\ud788":228,"\ub3c4\uc804\ud574\ubcf4\uace0":228,"\ub3c4\uc911\uc5d0":232,"\ub3c8\uc721\uc120\ubb3c":17,"\ub3c8\uc744":228,"\ub3cc\uc544\uac00\uace0":227,"\ub3cc\uc544\uac04\ub2e4\ub294":231,"\ub3cc\uc544\uc624\uac8c":227,"\ub3d9\ub5a8\uc5b4\uc9c4":228,"\ub3d9\uc2dc\ud638\uac00":17,"\ub3d9\uc548":232,"\ub3d9\uc548\ub9cc":230,"\ub3d9\uc548\uc5d0\ub9cc":230,"\ub3d9\uc6d0\uc0b0\uc5c5":230,"\ub3d9\uc758\ub97c":227,"\ub3d9\uc77c":30,"\ub3d9\uc77c\ud558\uac8c":[227,228,230],"\ub3d9\uc77c\ud558\uc9c0\ub9cc":45,"\ub3d9\uc77c\ud55c":[17,227,232],"\ub3d9\uc791":232,"\ub3d9\uc791\uacfc":29,"\ub3d9\uc791\uacfc\uc815\uc5d0\uc11c":232,"\ub3d9\uc791\uc774\ub2e4":228,"\ub3d9\uc791\uc911\uc778":230,"\ub3d9\uc791\ud558\ub294":232,"\ub3d9\uc791\ud558\ub294\uc9c0":[227,231],"\ub3d9\uc791\ud558\ub3c4\ub85d":232,"\ub3d9\uc791\ud55c\ub2e4":228,"\ub3d9\uc801\uc73c\ub85c":231,"\ub3d9\ud654\uc57d\ud488":231,"\ub418\uaca0\ub2e4":228,"\ub418\uace0":17,"\ub418\ub294":[227,228,231],"\ub418\ub354\uad70\uc694":231,"\ub418\ub3c4\ub85d":228,"\ub418\ub9ac\ub77c":232,"\ub418\uba74":[17,30,228,230,232],"\ub418\uba74\uc11c":[227,232],"\ub418\uc5b4":231,"\ub418\uc5b4\uc57c":231,"\ub418\uc5b4\uc788\ub294":[29,228,230],"\ub418\uc5b4\uc788\ub294\uac00":228,"\ub418\uc5b4\uc788\ub294\ub370":231,"\ub418\uc5b4\uc788\ub294\ub370\uc694":231,"\ub418\uc5b4\uc788\ub2e4\uba74":29,"\ub418\uc5b4\uc788\uc2b5\ub2c8\ub2e4":227,"\ub418\uc5b4\uc788\uc73c\uba70":230,"\ub418\uc5b4\uc788\uc9c0":29,"\ub418\uc5b4\uc788\uc9c0\ub9cc":231,"\ub418\uc5c8\ub294\uc9c0":[29,45],"\ub418\uc5c8\ub2e4":228,"\ub418\uc5c8\ub358":228,"\ub418\uc5c8\ub4e0":228,"\ub418\uc5c8\uc2b5\ub2c8\ub2e4":17,"\ub418\uc5c8\uc73c\uba74":228,"\ub418\uc9c0":[228,232],"\ub41c":228,"\ub41c\ub2e4":[228,230],"\ub420":[227,228],"\ub429\ub2c8\ub2e4":[17,227,231,232],"\ub450":[17,228],"\ub450\uac00\uc9c0":228,"\ub450\uac1c\uc758":232,"\ub450\uace0":228,"\ub450\ub294\ub370":228,"\ub450\ubc88\uc9f8":17,"\ub450\uc5c8\uc2b5\ub2c8\ub2e4":231,"\ub458":228,"\ub458\ub3c4":228,"\ub458\uc758":228,"\ub4a4":[29,45,48,232],"\ub4a4\uc5d0":[29,227,228,230,232],"\ub4e0\ub2e4":228,"\ub4e3\uace0":48,"\ub4e3\ub294":48,"\ub4e3\ub3c4\ub85d":230,"\ub4e3\uc9c0":230,"\ub4e4\uc5b4":[17,228,230,231,232],"\ub4e4\uc5b4\uac00\uac8c":228,"\ub4e4\uc5b4\ubcf4\uba74":231,"\ub4e4\uc5b4\ubcf4\uc790\uba74":228,"\ub4e4\uc5b4\uc624\ub294":[48,230],"\ub4e4\uc5b4\uc62c":232,"\ub4e4\uc5b4\uc634":23,"\ub4e4\uc5c8\uace0":231,"\ub4e4\uc5c8\ub2e4":228,"\ub4e4\uc5d0":230,"\ub4e4\uc5d0\uc11c\ub294":[45,48],"\ub4e4\uc744":45,"\ub4e4\uc778":[45,48],"\ub4e4\uc790\uba74":231,"\ub4ef":[17,228],"\ub4f1":[230,231,232],"\ub4f1\uacfc":230,"\ub4f1\ub4f1\uc5d0":231,"\ub4f1\ub77d\uc728":[230,231,232],"\ub4f1\ub85d":[17,45,48,232],"\ub4f1\ub85d\uac00\ub2a5\ud55c":17,"\ub4f1\ub85d\ub418\uc5b4":17,"\ub4f1\ub85d\ub418\uc5b4\uc838":17,"\ub4f1\ub85d\ub41c":[17,45,48,231],"\ub4f1\ub85d\ub420":[45,48],"\ub4f1\ub85d\ub429\ub2c8\ub2e4":17,"\ub4f1\ub85d\uc2dc":17,"\ub4f1\ub85d\uc740":17,"\ub4f1\ub85d\uc744":17,"\ub4f1\ub85d\uc774":17,"\ub4f1\ub85d\ud0c0\uc785":17,"\ub4f1\ub85d\ud0c0\uc785\uc744":17,"\ub4f1\ub85d\ud558\ub294":17,"\ub4f1\ub85d\ud55c":[17,23],"\ub4f1\ub85d\ud569\ub2c8\ub2e4":45,"\ub4f1\ub85d\ud574\uc57c\ud568":17,"\ub4f1\ub85d\ud574\uc9c0":17,"\ub4f1\uc5d0\uc11c":[230,231],"\ub4f1\uc73c\ub85c":29,"\ub4f1\uc744":231,"\ub4f1\uc758":[45,48,227,231],"\ub4f1\uc774":[45,48,231],"\ub4f1\uc9c0\uc5d0\uc11c":231,"\ub514\ub809\ud1a0\ub9ac\ub098":232,"\ub514\ubc14\uc774\uc2a4\uc774\uc5d4\uc9c0":230,"\ub514\ubc84\uae45\uc744":227,"\ub514\uc640\uc774\ud30c\uc6cc":230,"\ub514\uc790\uc778":231,"\ub514\uc790\uc778\ub418\uc5b4":231,"\ub514\uc790\uc778\uc740":231,"\ub515\uc154\ub108\ub9ac":[29,45],"\ub530\ub77c":[17,45,48,227,230,231],"\ub530\ub77c\uac00\ub2e4":231,"\ub530\ub77c\uac00\uc11c":232,"\ub530\ub77c\uc11c":[27,48,56,228,231,232],"\ub530\ub85c":[228,230],"\ub530\ub974\ub294\uac8c":17,"\ub530\ub974\uc2e0\ub2e4\uba74":231,"\ub530\ub978":17,"\ub531\ud788":228,"\ub54c":[17,23,48,228,231,232],"\ub54c\ub9c8\ub2e4":[227,231,232],"\ub54c\ubb38\uc5d0":[45,48,227,228,230,231,232],"\ub54c\ubb38\uc785\ub2c8\ub2e4":[227,231],"\ub5a0\uc624\ub974\uc9c0":228,"\ub5a0\uc624\ub978\ub2e4":228,"\ub5a8\uc5b4\uc9c0\uac8c":231,"\ub610":228,"\ub610\ub294":[17,23,86],"\ub610\ub2e4\ub978":17,"\ub610\ud55c":[228,230,231,232],"\ub611\uac19\uc774":[17,227,230],"\ub69d":228,"\ub728\ub294":232,"\ub728\ub294\ub370":227,"\ub73b\uc785\ub2c8\ub2e4":227,"\ub744\uc6b8":231,"\ub744\uc6cc\ub193\uc740":227,"\ub744\uc6cc\ub450\uace0":227,"\ub744\uc6cc\ub454":232,"\ub744\uc6cc\ubcf4\ub294":232,"\ub77c\uace0":227,"\ub77c\uc774\ube0c\ub7ec\ub9ac":227,"\ub77c\uc774\ube0c\ub7ec\ub9ac\uac00":[227,231],"\ub77c\uc774\ube0c\ub7ec\ub9ac\ub294":228,"\ub77c\uc774\ube0c\ub7ec\ub9ac\uc5d0\uc11c":231,"\ub77c\uc774\ube0c\ub7ec\ub9ac\uc758":231,"\ub77c\uc774\ube0c\ub7ec\ub9ac\ucc98\ub7fc":231,"\ub77c\uc774\uc120\uc2a4":231,"\ub77c\uc774\uc120\uc2a4\ub97c":231,"\ub77c\uc774\uc120\uc2a4\uc640":231,"\ub77c\uc774\uc120\uc2a4\uc758":231,"\ub77c\uc778\uc5d0\uc11c":232,"\ub798\ud37c":[45,231,232],"\ub7a9\uc9c0\ub178\ubbf9\uc2a4":230,"\ub808\ubc84\ub9ac\uc9c0":231,"\ub808\ubca8\uc5d0\uc11c":[45,48],"\ub808\ucf54\ub4dc":[17,23,228],"\ub808\ucf54\ub4dc\ub97c":228,"\ub808\ucf54\ub4dc\uba85":17,"\ub808\ucf54\ub4dc\uc758":17,"\ub808\ud3ec\uc9c0\ud1a0\ub9ac\ub97c":227,"\ub85c":[17,23,45,227,228,230,231,232],"\ub85c\uac70\uc758":[45,48],"\ub85c\uadf8\ub808\ubca8\uc744":[45,48],"\ub85c\uadf8\uc778":[17,23,29,227,228,230,232],"\ub85c\uadf8\uc778\uacfc":[228,232],"\ub85c\uadf8\uc778\uae4c\uc9c0":228,"\ub85c\uadf8\uc778\ub41c":232,"\ub85c\uadf8\uc778\uc2dc":86,"\ub85c\uadf8\uc778\uc744":[17,29,228,232],"\ub85c\uadf8\uc778\uc774":[17,29,228,230,232],"\ub85c\uadf8\uc778\ucc3d\uc5d0\uc11c":17,"\ub85c\uadf8\uc778\ucc3d\uc744":17,"\ub85c\uadf8\uc778\ucc98\ub9ac\ub97c":230,"\ub85c\uadf8\uc778\ud558\uba74\uc11c":232,"\ub85c\uadf8\uc778\ud55c":17,"\ub85c\ub294":17,"\ub85c\ub4dc":[29,45],"\ub85c\ub4dc\ub418\uc5c8\ub294\uc9c0":230,"\ub85c\ub4dc\ub428\uc744":[29,45],"\ub85c\ub4dc\ud55c":29,"\ub85c\ub4dc\ud55c\ub2e4":228,"\ub85c\ub9cc":231,"\ub85c\uc9c1\ub4e4\uc774":232,"\ub85c\uc9c1\uc5d0":[48,227],"\ub85c\uc9c1\uc744":231,"\ub85c\uceec\uc5d0":[23,228],"\ub85c\uceec\uc758":228,"\ub86f\ub370\uc815\ubc00\ud654\ud559":230,"\ub97c":[17,29,228,230,231,232],"\ub9ac\ubc84\uc2a4":228,"\ub9ac\uc2a4\ud06c\uac00":228,"\ub9ac\uc2a4\ud06c\ub294":228,"\ub9ac\uc2a4\ud2b8":[17,23,29,230],"\ub9ac\uc2a4\ud2b8\ub294":[17,23],"\ub9ac\uc2a4\ud2b8\ub85c":45,"\ub9ac\uc2a4\ud2b8\ub97c":17,"\ub9ac\uc5bc\ub370\uc774\ud130":17,"\ub9ac\uc5bc\uc794\uace0":231,"\ub9ac\uc5bc\uc794\uace0\ucd1d\ud569":231,"\ub9ac\uce20":[17,125,131,134],"\ub9ac\ud134":[17,29],"\ub9ac\ud134\uac12":[4,17],"\ub9ac\ud134\uac12\uc740":[45,48],"\ub9ac\ud134\uac12\uc774":17,"\ub9ac\ud134\ud569\ub2c8\ub2e4":17,"\ub9b4\ub9ac\uc988":227,"\ub9c1\ud06c\uac00":228,"\ub9c8\ub2e4":[23,230,231],"\ub9c8\uc2dc\uae30":23,"\ub9c8\uc6b0\uc2a4":232,"\ub9c8\uc74c\uba39\uace0":228,"\ub9c8\uc74c\uc5d0\uc11c":228,"\ub9c8\uc9c0\ub9c9":[17,227,228],"\ub9c8\uc9c0\ub9c9\uc5d0":17,"\ub9c8\uc9c0\ub9c9\uc73c\ub85c":232,"\ub9c8\ucc2c\uac00\uc9c0\ub85c":228,"\ub9c8\ucf13\ubcc4":231,"\ub9cc":232,"\ub9cc\uae30\uc77c":230,"\ub9cc\ub4e0":[17,231],"\ub9cc\ub4e4\uace0":[231,232],"\ub9cc\ub4e4\uba74":17,"\ub9cc\ub4e4\uc5b4":231,"\ub9cc\ub4e4\uc5b4\ub193\uc744":231,"\ub9cc\ub4e4\uc5b4\ub450\uace0":231,"\ub9cc\uc57d":[45,232],"\ub9cc\uc57d\uc5d0":[227,228,230,231,232],"\ub9cc\uc871":230,"\ub9cc\uc871\ud558\ub294":[228,230],"\ub9cc\uc871\ud558\uc9c0":228,"\ub9cc\ud07c":228,"\ub9cc\ud55c":231,"\ub9ce\uc2b5\ub2c8\ub2e4":231,"\ub9ce\uc544":231,"\ub9ce\uc740":[17,228,231],"\ub9ce\uc774":228,"\ub9d0\uace0":[230,231],"\ub9d0\uace0\ub3c4":228,"\ub9d0\uc544\uc57c":228,"\ub9de\uac8c":[17,228,231,232],"\ub9de\ub294":[17,228],"\ub9de\ub294\uc9c0":228,"\ub9de\ucdb0":[228,231],"\ub9de\ucdb0\uc11c":[17,231],"\ub9e1\uc544\uc11c":228,"\ub9e1\uc73c\uba70":232,"\ub9e4":230,"\ub9e4\uac1c\ubcc0\uc218":17,"\ub9e4\uac1c\ubcc0\uc218\ub97c":17,"\ub9e4\ub274\uc5bc":231,"\ub9e4\ub274\uc5bc\uc758":231,"\ub9e4\ub2c8\uc800":231,"\ub9e4\ub3c4":[17,45,48,230],"\ub9e4\ub3c41\ucc28\ud638\uac00":230,"\ub9e4\ub3c42\ucc28\ud638\uac00":230,"\ub9e4\ub3c43\ucc28\ud638\uac00":230,"\ub9e4\ub3c44\ucc28\ud638\uac00":230,"\ub9e4\ub3c45\ucc28\ud638\uac00":230,"\ub9e4\ub3c4\uac10\uc2dc\uc2dc\uc791":231,"\ub9e4\ub3c4\uac10\uc2dc\ud3ec\ucc29":231,"\ub9e4\ub3c4\uc218\uad6c\ubd84":[45,230],"\ub9e4\ub3c4\uc815\uc815":[17,45,152],"\ub9e4\ub3c4\ucde8\uc18c":[17,45,152],"\ub9e4\ub3c4\ud638\uac00":[230,231],"\ub9e4\ub9e4\uad6c\ubd84":[17,45,230],"\ub9e4\ubc88":[228,231,232],"\ub9e4\uc218":[17,45,48,230],"\ub9e4\uc2181\ucc28\ud638\uac00":230,"\ub9e4\uc2182\ucc28\ud638\uac00":230,"\ub9e4\uc2183\ucc28\ud638\uac00":230,"\ub9e4\uc2184\ucc28\ud638\uac00":230,"\ub9e4\uc2185\ucc28\ud638\uac00":230,"\ub9e4\uc218\uad6c\ubd84":230,"\ub9e4\uc218\ub294":[230,231],"\ub9e4\uc218\uc815\uc815":[17,45,152],"\ub9e4\uc218\uc8fc\ubb38\uc644\ub8cc":230,"\ub9e4\uc218\uc8fc\ubb38\ud558\ub294":17,"\ub9e4\uc218\ucc98\ub9ac":[230,231],"\ub9e4\uc218\ucde8\uc18c":[17,45,152],"\ub9e4\uc218\ud638\uac00":[230,231],"\ub9e4\uc77c":228,"\ub9e4\uc785\ub2e8\uac00":230,"\ub9e4\uc785\uc778\ub3c4\uccb4\uacb0":231,"\ub9e4\uc785\uc778\ub3c4\ud638\uac00":231,"\ub9e4\ucd9c\uc561":[230,231,232],"\ub9e4\ud06c\ub85c":230,"\ub9e4\ud06c\ub85c\uc640":228,"\ub9e4\ud551":23,"\ub9e4\ud551\ub418\ub294":23,"\ub9e4\ud551\ub41c\ub2e4":23,"\ub9e8":[227,228,232],"\uba38\ub9ac\uac00":228,"\uba3c\uc800":[17,45,48,227,228,230,231,232],"\uba40\uc5b4\uc9c0\uba74\uc11c":231,"\uba40\ud2f0\ub370\uc774\ud130\uac00":230,"\uba40\ud2f0\ub370\uc774\ud130\uc758":17,"\uba40\ud2f0\ucc28\ub2e8":231,"\uba54\ub274":228,"\uba54\ub274\ub97c":232,"\uba54\ub9ac\uce20\ud654\uc7ac":231,"\uba54\ubaa8\ub9ac\ubcf4\ud638":22,"\uba54\uc11c\ub4dc":232,"\uba54\uc11c\ub4dc\ub4e4\uc744":[231,232],"\uba54\uc11c\ub4dc\ub4e4\uc774":232,"\uba54\uc11c\ub4dc\ub97c":[231,232],"\uba54\uc11c\ub4dc\uc758":231,"\uba54\uc138\uc9c0":17,"\uba54\uc138\uc9c0\ub97c":48,"\uba54\uc18c\ub4dc":[45,48,231],"\uba54\uc18c\ub4dc\ub4e4\uc774":29,"\uba54\uc18c\ub4dc\ub85c":17,"\uba54\uc18c\ub4dc\ub97c":[45,48],"\uba54\uc2dc\uc9c0":[23,27,56,230,231],"\uba54\uc2dc\uc9c0\uac00":[23,232],"\uba54\uc2dc\uc9c0\ub85c":48,"\uba54\uc2dc\uc9c0\ub97c":[23,27,45,48,56],"\uba54\uc2dc\uc9c0\uc5d0":23,"\uba54\uc2dc\uc9c0\uc5d0\ub294":[27,56],"\uba54\uc2dc\uc9c0\uc758":[230,232],"\uba54\ud0c0\uc815\ubcf4\ub4e4\uc5d0":231,"\uba54\ud0c0\uc815\ubcf4\ub4e4\uc744":231,"\uba64\ubc84\ud568\uc218\ub85c\uc368":230,"\uba85":[17,23],"\uba85\ub839\ub4e4\uc740":232,"\uba85\ub839\uc5b4":232,"\uba85\ub839\uc5b4\ub97c":227,"\uba85\ub839\uc5b4\ub9cc":232,"\uba85\ub839\uc5b4\uc758":227,"\uba85\ub839\uc744":[227,232],"\uba85\ub839\uc774":232,"\uba85\ub839\ud615":231,"\uba85\uc138\uc5d0":231,"\uba85\uc2dc\ub41c":17,"\uba85\uc2dc\uc801\uc778":231,"\uba85\uce6d":86,"\uba87":231,"\uba87\uac00\uc9c0":[228,230],"\uba87\uba87":[45,48,231,232],"\ubaa8\ub2c8\ud130\ub9c1":231,"\ubaa8\ub450":[17,45,48,228,230],"\ubaa8\ub4c8":231,"\ubaa8\ub4c8\ub4e4\uc740":232,"\ubaa8\ub4c8\ub4e4\uc785\ub2c8\ub2e4":232,"\ubaa8\ub4c8\uc5d0\uc11c":232,"\ubaa8\ub4c8\uc758":17,"\ubaa8\ub4e0":[17,29,48,227,228,231,232],"\ubaa8\ub974\uaca0\ub2e4":228,"\ubaa8\ub974\uaca0\uc9c0\ub9cc":228,"\ubaa8\ub974\ub294":231,"\ubaa8\ub974\ub354\ub77c\ub3c4":231,"\ubaa8\uc758":231,"\ubaa8\uc758\uacc4\uc88c\uc5d0":232,"\ubaa8\uc758\ub9ac\uc5bc\uc794\uace0\ucd1d\ud569":231,"\ubaa8\uc758\uc8fc\ubb38\uccb4\uacb0":231,"\ubaa8\uc758\ud22c\uc790":[17,29,230,232],"\ubaa8\uc758\ud22c\uc790\ub294":227,"\ubaa8\uc758\ud22c\uc790\ub85c":232,"\ubaa8\uc758\ud22c\uc790\uc5d0\uc11c\ub294":[17,45,152],"\ubaa8\uc758\ud22c\uc790\uc758":232,"\ubaa8\uc758\ud604\ubb3c\uc794\uace0":231,"\ubaa9\ub85d":[17,45,48,230,232],"\ubaa9\ub85d\ub4e4\uc5d0":230,"\ubaa9\ub85d\ub97c":29,"\ubaa9\ub85d\uc5d0":[45,48],"\ubaa9\ub85d\uc5d0\uc11c":[230,231],"\ubaa9\ub85d\uc740":[230,232],"\ubaa9\ub85d\uc744":[17,29,45,48],"\ubaa9\ub85d\uc758":232,"\ubaa9\ub85d\uc911":29,"\ubaa9\uc801\uc5d0":228,"\ubaa9\uc801\uc73c\ub85c":17,"\ubaa9\uc801\uc774\ubbc0\ub85c":232,"\ubabb":228,"\ubabb\ud558\uace0":228,"\ubabb\ud558\ub294":232,"\ubabb\ud574\ub3c4":231,"\ubb34\uad00\ud569\ub2c8\ub2e4":17,"\ubb34\ub824":228,"\ubb34\ub9ac\uac00":231,"\ubb34\uc2dd\ud558\uac8c":228,"\ubb34\uc5c7\uc774":228,"\ubb38\uc11c":[231,232],"\ubb38\uc11c\ub294":228,"\ubb38\uc11c\ub97c":231,"\ubb38\uc11c\uc0c1\uc73c\ub85c\ub9cc":17,"\ubb38\uc11c\uc0c1\uc758":17,"\ubb38\uc11c\uc5d0\uc11c":[4,228],"\ubb38\uc11c\uc5d0\uc11c\ub3c4":231,"\ubb38\uc744":231,"\ubb38\uc758\ud574\ubcf8":228,"\ubb38\uc790\uc5f4":[17,45,48,230,231],"\ubb38\uc790\uc5f4\ub4e4\ub85c":17,"\ubb38\uc790\uc5f4\uc785\ub2c8\ub2e4":17,"\ubb38\uc81c\uac00":[227,228,231],"\ubb38\uc81c\ub4e4\uc744":231,"\ubb38\uc81c\ub97c":[29,227],"\ubb38\uc81c\uc5c6\uc2b5\ub2c8\ub2e4":227,"\ubb38\uc81c\uc5c6\uc774":231,"\ubb38\uc81c\uc774\ub2e4":228,"\ubb3b\uc9c0":232,"\ubb3c\ub860":227,"\ubb54":228,"\ubb58\uae4c":228,"\ubba4\ucd94\uc5bc\ud380\ub4dc":[17,125,131,134],"\ubbf8\uacb0\uc81c\uc57d\uc815":[230,231],"\ubbf8\uacb0\uc81c\uc804\uc77c\ub300\ube44":[230,231],"\ubbf8\uad6d\uc785\ucd9c\uace0":231,"\ubbf8\uad6d\uc885\ubaa9\ubcc0\uacbd":231,"\ubbf8\ub2c8\uae08\uc120\ubb3c":17,"\ubbf8\ub2c8\uba40\ud55c":232,"\ubbf8\ub798\uc5d0\uc14b":231,"\ubbf8\ub9ac":[228,230,231,232],"\ubbf8\uc124\uc815":17,"\ubbf8\uc2e0\uccad":86,"\ubbf8\uc811\uc18d\uc0c1\ud0dc":86,"\ubbf8\uccb4\uacb0":45,"\ubbf8\uccb4\uacb0\uc218\ub7c9":[230,231],"\ubbf8\uccb4\uacb0\uc2dc":17,"\ubbf8\uccb4\uacb0\ud1b5\ubcf4\uc2dc\uc2a4\ud15c":231,"\ubbf8\ud22c\uc820":230,"\ubbf8\ud3ec\ud568":17,"\ubbf8\ud3ec\ud568\uc2dc":17,"\ubc0f":[17,29,45,48,227,228,230,232],"\ubc11\uc758":228,"\ubc14\uafc0":17,"\ubc14\ub00c\ub294":228,"\ubc14\ub00c\uba74\uc11c":227,"\ubc14\ub780\ub2e4":[228,230],"\ubc14\ub78c\uc9c1\ud558\uc9c0":228,"\ubc14\ub78c\uc9c1\ud560":17,"\ubc14\ub78d\ub2c8\ub2e4":[17,23,231,232],"\ubc14\ub85c":[227,228,230,231],"\ubc14\ub85c\ubc14\ub85c":231,"\ubc14\ud034\ub97c":228,"\ubc15\uc2a4\ub97c":232,"\ubc16\uc5d0":227,"\ubc18\ub4dc\uc2dc":[17,231],"\ubc18\uba74\uc5d0":[228,232],"\ubc18\ubcf5":17,"\ubc18\ubcf5\uac1c\uc218":17,"\ubc18\ubcf5\uac1c\uc218\ub97c":17,"\ubc18\ubcf5\uc218":17,"\ubc18\ubcf5\uc21c\uc11c\uc640":17,"\ubc18\ubcf5\ud69f\uc218":17,"\ubc18\ubcf5\ud69f\uc218\ub97c":17,"\ubc18\ube44\ub840\ud558\uac8c":228,"\ubc18\uc601\ud560":48,"\ubc18\ud658":[17,230,231],"\ubc18\ud658\uac12\uc758":17,"\ubc18\ud658\ub418\uae30":230,"\ubc18\ud658\ub418\ub294":[230,232],"\ubc18\ud658\ub418\ub294\ub370":230,"\ubc18\ud658\ub418\uba70":45,"\ubc18\ud658\ub41c\ub2e4":230,"\ubc18\ud658\ub429\ub2c8\ub2e4":[45,48],"\ubc18\ud658\ubc1b\uc2b5\ub2c8\ub2e4":45,"\ubc18\ud658\ud558\ub294":[230,232],"\ubc18\ud658\ud558\ub294\ub370":230,"\ubc18\ud658\ud558\uc9c0\ub9cc":17,"\ubc18\ud658\ud55c\ub2e4":[17,230],"\ubc18\ud658\ud569\ub2c8\ub2e4":[17,29,45,48],"\ubc18\ud658\ud588\ub2e4\uba74":48,"\ubc1b\uac8c":228,"\ubc1b\uace0":17,"\ubc1b\uace0\uc790":228,"\ubc1b\uae30":228,"\ubc1b\ub294":23,"\ubc1b\ub294\ub2e4":17,"\ubc1b\uc544":[48,227],"\ubc1b\uc544\uc11c":[17,231],"\ubc1b\uc544\uc57c":228,"\ubc1b\uc544\uc624\ub294":[17,228],"\ubc1b\uc544\uc628\ub2e4":17,"\ubc1b\uc544\uc62c\uc218\ub9cc":228,"\ubc1b\uc73c\uc138\uc694":227,"\ubc1b\uc740":[23,228,231],"\ubc1b\uc744":[17,23,227,228],"\ubc1b\uc9c0":[45,48],"\ubc1c\uacac\ub418\uba74":228,"\ubc1c\uacac\ud558\uac8c":231,"\ubc1c\uacac\ud55c":[230,231],"\ubc1c\uba85\ud558\ub294":228,"\ubc1c\uc0dd\ub418\ub294":23,"\ubc1c\uc0dd\ub420\ub54c":17,"\ubc1c\uc0dd\ub429\ub2c8\ub2e4":[17,23],"\ubc1c\uc0dd\uc2dc":48,"\ubc1c\uc0dd\uc2dc\ud0a8":30,"\ubc1c\uc0dd\uc2dc\ud0b5\ub2c8\ub2e4":[45,48],"\ubc1c\uc0dd\ud558\uac8c":228,"\ubc1c\uc0dd\ud558\uace0":[17,45,48],"\ubc1c\uc0dd\ud558\ub294":[23,29,45,48,227,228,231,232],"\ubc1c\uc0dd\ud558\uba74":48,"\ubc1c\uc0dd\ud560":[23,29,45,48,227,231],"\ubc1c\uc0dd\ud569\ub2c8\ub2e4":[45,48],"\ubc29\ubb38\ud574\uc11c":227,"\ubc29\ubc95":227,"\ubc29\ubc95\uc73c\ub85c":[17,228],"\ubc29\ubc95\uc740":[227,232],"\ubc29\ubc95\uc774":227,"\ubc29\ubc95\uc774\uba70":17,"\ubc29\uc2dd":231,"\ubc29\uc2dd\ub300\ub85c":231,"\ubc29\uc2dd\ub3c4":228,"\ubc29\uc2dd\ub4e4\ub85c\ub3c4":231,"\ubc29\uc2dd\uc5d0":231,"\ubc29\uc2dd\uc5d0\ub294":231,"\ubc29\uc2dd\uc5d0\uc11c":231,"\ubc29\uc2dd\uc5d0\uc11c\uc758":231,"\ubc29\uc2dd\uc73c\ub85c":[228,230,231],"\ubc29\uc2dd\uc73c\ub85c\ub294":231,"\ubc29\uc2dd\uc73c\ub85c\ub3c4":[228,231,232],"\ubc29\uc2dd\uc740":228,"\ubc29\uc2dd\uc744":228,"\ubc29\uc2dd\uc774":[228,232],"\ubc29\uc2dd\uc774\ub2e4":[230,232],"\ubc29\ud5a5\uc131\uc744":231,"\ubc29\ud5a5\uc73c\ub85c":[228,231],"\ubc29\ud654\ubcbd":[17,29],"\ubc30\uc5f4":17,"\ubc30\uc5f4\ub85c":17,"\ubc30\uc5f4\uc744":17,"\ubc30\uce58\ub370\uc774\ud130\uac31\uc2e0":231,"\ubc30\ud3ec":231,"\ubc30\ud3ec\ub418\uace0":231,"\ubc30\ud3ec\ub418\uba70":231,"\ubc30\ud3ec\ub418\uc5b4\uc57c":231,"\ubc30\ud3ec\ud310\uc5d0\uc11c":227,"\ubc84\uc804":[17,29,227,232],"\ubc84\uc804\uacfc":227,"\ubc84\uc804\uc5d0":227,"\ubc84\uc804\uc73c\ub85c":[227,228],"\ubc84\uc804\uc740":227,"\ubc84\uc804\uc744":[227,232],"\ubc84\uc804\uc774":227,"\ubc84\uc804\ucc98\ub9ac":[22,23,232],"\ubc84\uc804\ucc98\ub9ac\uac00":[86,232],"\ubc84\uc804\ucc98\ub9ac\ub97c":232,"\ubc84\uc804\ucc98\ub9ac\uc5d0":232,"\ubc84\ud2bc":[228,231],"\ubc84\ud2bc\uc744":[228,231,232],"\ubc84\ud2bc\uc774":228,"\ubc88":[227,232],"\ubc88\uac70\ub85c\uc6b4":[228,231],"\ubc88\uac70\ub85c\uc6b8":228,"\ubc88\uac70\ub85c\uc6c0\uc774":[228,232],"\ubc8c":228,"\ubc8c\uc5b4\uc9c4":17,"\ubc94\uc704\uac00":228,"\ubc95\ub960\uc801":231,"\ubca0\uac00":[230,231],"\ubcc0\uacbd\ub41c":231,"\ubcc0\uacbd\ub420":[23,27,56,231],"\ubcc0\uacbd\uc774":231,"\ubcc0\uacbd\ud558\uc5ec":17,"\ubcc0\uacbd\ud560":231,"\ubcc0\ub3d9\ub7c9\uc744":228,"\ubcc0\ub3d9\uc774":228,"\ubcc0\ud658":45,"\ubcc0\ud658\uc744":230,"\ubcc0\ud658\ud558\uc5ec":[29,230,231],"\ubcc0\ud658\ud574\uc11c":230,"\ubcc4\ub2e4\ub978":[29,45,228,232],"\ubcc4\ub3c4":[228,230,232],"\ubcc4\ub3c4\ub85c":[45,48,228,230],"\ubcc4\ub3c4\uc758":[45,48,228,230],"\ubcf4\uad00\uc815\ucc45\uc774":228,"\ubcf4\uae30\uc5d0\ub294":228,"\ubcf4\ub0b4":48,"\ubcf4\ub294\ub370":231,"\ubcf4\ub2c8":[228,232],"\ubcf4\ub2e4":[17,231],"\ubcf4\uba74":[228,231],"\ubcf4\uc138\uc694":231,"\ubcf4\uc544":17,"\ubcf4\uc548":[17,29,48],"\ubcf4\uc720\uacc4\uc88c":17,"\ubcf4\uc720\uacc4\uc88c\ubc88\ud638":45,"\ubcf4\uc720\uc218\ub7c9":[230,231],"\ubcf4\uc774\ub294":228,"\ubcf4\uc778\ub2e4":228,"\ubcf4\uc7a5\ud558\ub3c4\ub85d":[29,45],"\ubcf4\uc7a5\ud55c":29,"\ubcf4\uc815\ud558\ub294\uac74":228,"\ubcf4\uc870\uc9c0\ud45c\ub4e4\uc744":228,"\ubcf5\uc218\uac1c\uc758":[45,48],"\ubcf5\uc218\ub370\uc774\ud130":17,"\ubcf5\uc218\uc885\ubaa9":17,"\ubcf5\uc218\uc885\ubaa9\uac00\ub2a5":17,"\ubcf5\uc218\uc885\ubaa9\uc815\ubcf4\uc694\uccad":17,"\ubcf5\uc218\uc885\ubaa9\uc870\ud68c":17,"\ubcf5\uc7a1\ud558\uac8c":232,"\ubcf8\uc804\ub3c4":228,"\ubcfc":[228,231],"\ubd09\ucc29\ud55c":228,"\ubd24\ub358":228,"\ubd24\uc744":[228,231],"\ubd24\uc744\ub54c":228,"\ubd80\uac00\uae30\ub2a5\ub4e4\uc744":231,"\ubd80\ub2f4\ub418\uc9c0":228,"\ubd80\ub2f4\uc2a4\ub7fd\uc9c0":228,"\ubd80\ub2f4\uc774":228,"\ubd80\ubd84\ub3c4":228,"\ubd80\ubd84\ub4e4\uc774":231,"\ubd80\ubd84\uc744":230,"\ubd80\ubd84\uc774":228,"\ubd80\ubd84\uc774\ub2c8":227,"\ubd80\ubd84\uc774\ub2e4":228,"\ubd80\ubd84\uc774\ub77c":232,"\ubd80\uc871\uc73c\ub85c":23,"\ubd80\ud130":[227,228],"\ubd84":45,"\ubd84\ub4e4\uaed8\uc11c":228,"\ubd84\ub958\ud558\uc2dc\uba74":[27,56],"\ubd84\ubd09":[228,231],"\ubd84\uc11d":231,"\ubd84\uc11d\uc5d0":228,"\ubd84\uc11d\uc744":228,"\ubd84\uc11d\ud574":228,"\ubd84\uc11d\ud574\ubcf4\uace0":228,"\ubd84\ud560\ub9e4\ub9e4":231,"\ubd84\ud560\ubc18\ubcf5\uc8fc\ubb38":231,"\ubd88\uacfc\ud558\ub2e4":228,"\ubd88\ub7ec\uc624\uac70\ub098":227,"\ubd88\ub7ec\uc624\uae30":[23,228],"\ubd88\ub7ec\uc624\ub294":227,"\ubd88\ub7ec\uc624\ub294\ub370":[45,48],"\ubd88\ub7ec\uc624\ub3c4\ub85d":[29,45],"\ubd88\ub7ec\uc624\uc9c0":[29,45],"\ubd88\ub7ec\uc628":[29,45,227,230],"\ubd88\ub7ec\uc628\ub2e4":230,"\ubd88\ub7ec\uc635\ub2c8\ub2e4":[29,45,227],"\ubd88\ub7ec\uc640\uc57c":230,"\ubd88\ub9ac\uc5b8":[29,45,48],"\ubd88\ub9cc\uc871\ud558\ub294":230,"\ubd88\ud544\uc694\ud55c":232,"\ubd99\uac8c":231,"\ube44\uace0":17,"\ube44\uace0\ucc38\uace0":17,"\ube44\uad50\uc801":[228,231],"\ube44\uad50\ud574\ubcf4\ub2c8":228,"\ube44\uad50\ud574\ubcf4\uc790":228,"\ube44\uad50\ud574\ubcf8\ub2e4":228,"\ube44\uad50\ud574\ubd24\ub2e4":228,"\ube44\uad50\ud588\uc744":232,"\ube44\ub85d":227,"\ube44\ubc00\ubc88\ud638":[17,22,23,29,45,230,232],"\ube44\ubc00\ubc88\ud638\uac00":232,"\ube44\ubc00\ubc88\ud638\ub85c":232,"\ube44\ubc00\ubc88\ud638\ub97c":232,"\ube44\ubc00\ubc88\ud638\uc785\ub825\ub9e4\uccb4\uad6c\ubd84":45,"\ube44\uc2b7\ud558\uac8c":[228,231],"\ube44\uc2b7\ud55c":228,"\ube44\uc728":[17,29,228],"\ube44\uc728\ub9cc\ud07c":228,"\ube44\uc728\uc744":228,"\ube44\ud574\uc11c":232,"\ube45\ub370\uc774\ud130\uae09\uc0c1\uc2b9":231,"\ube45\ub370\uc774\ud130\ub274\uc2a4":231,"\ube45\ub370\uc774\ud130\uc885\ubaa910\ubd84":231,"\ube45\ub370\uc774\ud130\uc885\ubaa91\ubd84":231,"\ube45\ub370\uc774\ud130\uc885\ubaa91\uc2dc\uac04":231,"\ube45\ub370\uc774\ud130\uc885\ubaa930\ucd08":231,"\ube45\ub370\uc774\ud130\uc885\ubaa9\ub2f9\uc77c":231,"\ube4c\ud2b8\uc778":232,"\ube60\ub974\uac8c":[228,232],"\ube60\ub974\ub2e4":228,"\ube60\uc838\ub098\uc635\ub2c8\ub2e4":227,"\ube68\uac04\uc0c9":232,"\ube68\uac04\uc0c9\uc758":232,"\ube68\ub77c\uc9c8":228,"\ube7c\uba74":228,"\ubfd0\ub9cc":[228,230],"\ubfd0\uc774\ub2e4":228,"\uc0ac\ub78c\ub4e4\uc5d0\uac8c":228,"\uc0ac\ub78c\ub4e4\uc740":228,"\uc0ac\ub78c\uc740":228,"\uc0ac\ub78c\uc774":228,"\uc0ac\ubcf8\uc744":227,"\uc0ac\uc2e4":[228,230,231],"\uc0ac\uc2e4\uc740":228,"\uc0ac\uc57c":228,"\uc0ac\uc6a9":[5,17,30,45,228,230,232],"\uc0ac\uc6a9\ub418\ub294":[29,230,231],"\uc0ac\uc6a9\ub41c":17,"\uc0ac\uc6a9\ub420":[29,228],"\uc0ac\uc6a9\ubaa9\uc801\uc5d0":228,"\uc0ac\uc6a9\ubc29\uc2dd\uc740":232,"\uc0ac\uc6a9\ubc95\uacfc":[230,231],"\uc0ac\uc6a9\ubc95\uc5d0":[227,231],"\uc0ac\uc6a9\ubc95\uc740":17,"\uc0ac\uc6a9\ubd88\uac00":23,"\uc0ac\uc6a9\uc0c1":17,"\uc0ac\uc6a9\uc2dc":[17,29],"\uc0ac\uc6a9\uc548\ud568":[23,45],"\uc0ac\uc6a9\uc73c\ub85c":231,"\uc0ac\uc6a9\uc740":228,"\uc0ac\uc6a9\uc744":230,"\uc0ac\uc6a9\uc774":[228,232],"\uc0ac\uc6a9\uc790":[17,23,27,29,45,56,230,231,232],"\uc0ac\uc6a9\uc790\uac00":[17,231],"\uc0ac\uc6a9\uc790\ub294":231,"\uc0ac\uc6a9\uc790\ub4e4\uc774":231,"\uc0ac\uc6a9\uc790\uc5d0\uac8c":231,"\uc0ac\uc6a9\uc790\uc758":[17,231],"\uc0ac\uc6a9\uc790\uc815\ubcf4":22,"\uc0ac\uc6a9\uc808\ucc28\uc758":227,"\uc0ac\uc6a9\ud558\uae30":[17,45,48,230,231,232],"\uc0ac\uc6a9\ud558\ub294":[17,227,228,231,232],"\uc0ac\uc6a9\ud558\ub294\uac74":228,"\uc0ac\uc6a9\ud558\ub294\uac83\uc73c\ub85c":228,"\uc0ac\uc6a9\ud558\ub294\uac8c":[17,228],"\uc0ac\uc6a9\ud558\ub294\ub370":231,"\uc0ac\uc6a9\ud558\ub3c4\ub85d":231,"\uc0ac\uc6a9\ud558\ub824":231,"\uc0ac\uc6a9\ud558\ub824\ub294":231,"\uc0ac\uc6a9\ud558\uba74":[228,232],"\uc0ac\uc6a9\ud558\uba74\uc11c":227,"\uc0ac\uc6a9\ud558\uc2dc\uae30":[17,231],"\uc0ac\uc6a9\ud558\uc2dc\ub294":232,"\uc0ac\uc6a9\ud558\uc5ec":231,"\uc0ac\uc6a9\ud558\uc9c0":[17,23,45,48,228,232],"\uc0ac\uc6a9\ud558\uc9c4":[45,48],"\uc0ac\uc6a9\ud55c":17,"\uc0ac\uc6a9\ud55c\ub2e4":[17,228,230],"\uc0ac\uc6a9\ud55c\ub2e4\uba74":231,"\uc0ac\uc6a9\ud560":[17,29,45,48,86,227,228,230,231,232],"\uc0ac\uc6a9\ud560\uc218":17,"\uc0ac\uc6a9\ud569\ub2c8\ub2e4":17,"\uc0ac\uc6a9\ud574":[29,231,232],"\uc0ac\uc6a9\ud574\ubcf4\uae30\ub85c":228,"\uc0ac\uc6a9\ud574\uc11c":228,"\uc0ac\uc6a9\ud574\uc57c":[17,228,231],"\uc0ac\uc720":[45,48],"\uc0ac\uc774\ub4dc\uc5d0\uc11c":232,"\uc0ac\uc774\ub4dc\uc758":232,"\uc0ac\uc774\ub97c":228,"\uc0ac\uc774\uc5d0":[17,228,231],"\uc0ac\uc774\uc5d0\uc11c\ub3c4":228,"\uc0ac\uc774\uc758":228,"\uc0ac\uc774\ud2b8\uc0c1\uc5d0\uc11c":228,"\uc0ad\uc81c\uac00":227,"\uc0ad\uc81c\ub97c":227,"\uc0ad\uc81c\uc2dc\ud0a8\ub2e4":17,"\uc0ad\uc81c\uc758":227,"\uc0ad\uc81c\ud569\ub2c8\ub2e4":29,"\uc0b0\uc815\ud558\ub294":228,"\uc0bc\uc131\uc804\uc790":[230,232],"\uc0bc\uc131\uc804\uc790\uc758":230,"\uc0bc\uc591\uc2dd\ud488":[230,231],"\uc0bc\uc591\ud1b5\uc0c1":230,"\uc0bc\uc591\ud640\ub529\uc2a4":231,"\uc0bd\uc9c8":228,"\uc0bd\uc9c8\ub4e4\uc740":228,"\uc0bd\uc9c8\uc744":228,"\uc0bd\uc9c8\ud558\uba74\uc11c":228,"\uc0c1\ub300\uc801\uc73c\ub85c":228,"\uc0c1\uc138\ud558\uac8c":17,"\uc0c1\uc2dc":[227,232],"\uc0c1\uc704":232,"\uc0c1\uc704\uc758":232,"\uc0c1\uc704\ud568\uc218\ub97c":230,"\uc0c1\uc7a5":[29,228],"\uc0c1\uc7a5\uc77c":17,"\uc0c1\uc7a5\uc77c\uc744":17,"\uc0c1\uc7a5\uc8fc\uc2dd":[230,231,232],"\uc0c1\uc7a5\uc8fc\uc2dd\uc218":17,"\uc0c1\uc7a5\uc8fc\uc2dd\uc218\ub97c":17,"\uc0c1\uc7a5\ud3d0\uc9c0":228,"\uc0c1\uc7a5\ud3d0\uc9c0\uac00":228,"\uc0c1\uc7a5\ud3d0\uc9c0\uc640":228,"\uc0c1\uc7a5\ud558\ub294":228,"\uc0c1\ud0dc\uac12\uc774":29,"\uc0c1\ud0dc\uac12\uc911":29,"\uc0c1\ud0dc\ub294":17,"\uc0c1\ud0dc\ub85c":17,"\uc0c1\ud0dc\ub97c":[17,29],"\uc0c1\ud0dc\uc5ec\uc57c":232,"\uc0c1\ud0dc\uc774\ub2e4":230,"\uc0c1\ud488\uc73c\ub85c":228,"\uc0c1\ud558\ud55c\uac00\ud3ed\ubcc0\uacbd":231,"\uc0c1\ud55c\uac00":[230,231,232],"\uc0c1\ud638\uc791\uc6a9":232,"\uc0c1\ud669\uc5d0":232,"\uc0c1\ud669\uc5d0\uc11c\ub294":[45,48,228],"\uc0c1\ud669\uc5d0\uc120":17,"\uc0c1\ud669\uc774":[45,48],"\uc0c1\ud669\uc774\ubbc0\ub85c":230,"\uc0c8\ub85c":[230,232],"\uc0c8\ub85c\uc6b4":[48,232],"\uc0dd\uac01\ub418\uc9c4":231,"\uc0dd\uac01\ub429\ub2c8\ub2e4\ub9cc":231,"\uc0dd\uac01\ub9cc":228,"\uc0dd\uac01\uc740":228,"\uc0dd\uac01\uc744":228,"\uc0dd\uac01\uc774":[228,231],"\uc0dd\uac01\uc774\ub2e4":228,"\uc0dd\uac01\ud55c\ub2e4":228,"\uc0dd\uac01\ud560":228,"\uc0dd\uac01\ud569\ub2c8\ub2e4":232,"\uc0dd\uac01\ud574\ub0b8":228,"\uc0dd\uac01\ud574\ubcfc":228,"\uc0dd\uac01\ud588\uc2b5\ub2c8\ub2e4":231,"\uc0dd\uacbc\ub294\uc9c0\ub97c":231,"\uc0dd\uae30\uac8c":232,"\uc0dd\uae30\ub294":[17,232],"\uc0dd\uc0b0\uc131\uc774":231,"\uc0dd\uc131":[17,228,230],"\uc0dd\uc131\ub418\ub294":29,"\uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4":231,"\uc0dd\uc131\uc2dc":48,"\uc0dd\uc131\uc2dc\uc5d0":230,"\uc0dd\uc131\ud558\uae30":232,"\uc0dd\uc131\ud558\ub294":228,"\uc0dd\uc131\ud558\ub3c4\ub85d":231,"\uc0dd\uc131\ud558\uc5ec":232,"\uc11c\ub4dc\ud30c\ud2f0":231,"\uc11c\ub4dc\ud30c\ud2f0\ub4e4\uc5d0\uc11c\ub294":231,"\uc11c\ub85c":17,"\uc11c\ubc84":[17,23,29,45,48,86,230,232],"\uc11c\ubc84\uac00":232,"\uc11c\ubc84\ub3c4":231,"\uc11c\ubc84\ub85c":17,"\uc11c\ubc84\ub97c":232,"\uc11c\ubc84\ub9c8\ub2e4":23,"\uc11c\ubc84\ub9cc":227,"\uc11c\ubc84\uc5d0":[17,29,45,48,227,228,230],"\uc11c\ubc84\uc5d0\uc11c":[17,27,48,56],"\uc11c\ubc84\uc5d0\uc11c\ub294":[45,48,231],"\uc11c\ubc84\uc640":[17,232],"\uc11c\ubc84\uc640\uc758":17,"\uc11c\ubc84\uc758":29,"\uc11c\ubc84\uc811\uc18d":[22,23],"\uc11c\ubc84\uce21":48,"\uc11c\ubc84\uce21\uc5d0":48,"\uc11c\ubc84\uce21\uc5d0\uc11c":[45,48],"\uc11c\ubc84\uce21\uc5d0\uc11c\ub294":48,"\uc11c\ubc84\uce21\uc73c\ub85c":48,"\uc11c\ubc84\uce21\uc758":48,"\uc11c\ubc84\ud1b5\uc2e0":[17,23,27,56],"\uc11c\ube44\uc2a4":228,"\uc11c\ube44\uc2a4\uc758":232,"\uc120\ubb3c":[17,231],"\uc120\ubb3c\uae30\ucd08\uc790\uc0b0\uc2dc\uc138":231,"\uc120\ubb3c\uc2dc\uc138":231,"\uc120\ubb3c\uc635\uc158":17,"\uc120\ubb3c\uc635\uc158\uc6b0\uc120\ud638\uac00":231,"\uc120\ubb3c\uc635\uc158\ud569\uacc4":231,"\uc120\ubb3c\uc774\ub860\uac00":231,"\uc120\ubb3c\ud638\uac00\uc794\ub7c9":231,"\uc120\uc635\uc2e4\uc2dc\uac04\uc99d\uac70\uae08\uc0b0\ucd9c\uc694\uccad":231,"\uc120\ud0dd":[17,231],"\uc120\ud0dd\uacfc":231,"\uc120\ud0dd\ubc29\uc2dd\uacfc":228,"\uc120\ud0dd\uc0ac\ud56d\uc785\ub2c8\ub2e4":227,"\uc120\ud0dd\uc801\uc73c\ub85c":230,"\uc120\ud0dd\ud558\uc138\uc694":231,"\uc120\ud0dd\ud558\uc2dc\uba74":231,"\uc120\ud0dd\ud574":[228,231],"\uc120\ud0dd\ud615":228,"\uc120\ud638\ud558\uc2dc\uba74":231,"\uc124\uba85\uacfc":17,"\uc124\uba85\ubb38":231,"\uc124\uba85\ubb38\uc744":232,"\uc124\uba85\uc744":17,"\uc124\uba85\ud558\uac70\ub098":228,"\uc124\uba85\ud558\uace0":232,"\uc124\uba85\ud558\ub294":228,"\uc124\uba85\ud558\uc790\uba74":228,"\uc124\uba85\ud569\ub2c8\ub2e4":[227,232],"\uc124\uba85\ud588\ub358":228,"\uc124\uc815":[17,29,228,230,232],"\uc124\uc815\uacfc":232,"\uc124\uc815\ub418\uc5b4":[29,230],"\uc124\uc815\ub41c":[45,48,230,231],"\uc124\uc815\ubd80\ud130":232,"\uc124\uc815\uc2dc":[17,29],"\uc124\uc815\uc5d0":17,"\uc124\uc815\uc740":228,"\uc124\uc815\uc744":[29,232],"\uc124\uc815\uc774":[228,230],"\uc124\uc815\uc778":17,"\uc124\uc815\ucc3d\uc744":29,"\uc124\uc815\ud30c\uc77c":232,"\uc124\uc815\ud30c\uc77c\uc744":232,"\uc124\uc815\ud30c\uc77c\uc758":232,"\uc124\uc815\ud558\uace0":232,"\uc124\uc815\ud558\ub294\uc9c0":232,"\uc124\uc815\ud558\ub354\ub77c\ub3c4":228,"\uc124\uc815\ud558\ub3c4\ub85d":232,"\uc124\uc815\ud558\uba74":[17,232],"\uc124\uc815\ud55c\ub2e4":230,"\uc124\uc815\ud560":17,"\uc124\uc815\ud569\ub2c8\ub2e4":[29,45,48],"\uc124\uc815\ud574":[228,230,232],"\uc124\uc815\ud574\ub193\uc73c\uba74":232,"\uc124\uc815\ud574\ub450\uc5c8\ub354\ub77c\ub3c4":232,"\uc124\uc815\ud588\ub2e4\uace0":228,"\uc124\uce58":[17,231,232],"\uc124\uce58\uac00":[227,231],"\uc124\uce58\uae4c\uc9c0\uc758":227,"\uc124\uce58\ub294":227,"\uc124\uce58\ub418\uc5b4":[227,231],"\uc124\uce58\ub418\uc5b4\uc57c":227,"\uc124\uce58\ub41c":228,"\uc124\uce58\ub97c":227,"\uc124\uce58\ubc29\ubc95\uacfc":231,"\uc124\uce58\ud30c\uc77c\uc744":227,"\uc124\uce58\ud558\uae30":227,"\uc124\uce58\ud558\ub294":227,"\uc124\uce58\ud558\ub294\ub370":227,"\uc124\uce58\ud558\uba74":227,"\uc124\uce58\ud560":227,"\uc124\uce58\ud569\ub2c8\ub2e4":227,"\uc131\uaca9\uc73c\ub85c":228,"\uc131\uacf5":[17,23],"\uc131\uacf5\uc5ec\ubd80":23,"\uc131\uacf5\uc774\uba70":17,"\uc131\uacf5\uc774\uba74":23,"\uc131\uacf5\ud558\uac70\ub098":17,"\uc131\uacf5\ud558\uba74":17,"\uc138\uac00\uc9c0":48,"\uc138\ubd80\uc801\uc778":232,"\uc138\uc0c1\uc774\ub2e4":228,"\uc140":228,"\uc14b\ud305\ud569\ub2c8\ub2e4":17,"\uc14b\ud305\ud574\uc57c":17,"\uc18c\uac1c\ud558\uace0":231,"\uc18c\uc18d\ub41c":17,"\uc18c\uc1a1\uc774":231,"\uc18c\uc218\uc810":17,"\uc18c\uc218\uc810\uc774":17,"\uc18c\uc22b\uc810\uc73c\ub85c":45,"\uc18c\uc22b\uc810\ud45c\ud604":45,"\uc18c\uc2a4\ub4e4\ub85c":228,"\uc18c\uc2a4\ub4e4\uc5d0\uc11c":228,"\uc18c\uc2a4\ub97c":228,"\uc18c\uc2a4\uc774\uc9c0\ub9cc":228,"\uc18c\uc2a4\uc911":228,"\uc18c\uc2a4\ucf54\ub4dc":227,"\uc18c\uc2a4\ucf54\ub4dc\ub294":227,"\uc18c\uc561\ucc44\uad8c\uccb4\uacb0":231,"\uc18c\uc561\ucc44\uad8c\ud638\uac00\uc794\ub7c9":231,"\uc18c\uc5c5\uc885\uad6c\ubd84":[228,230,231],"\uc18c\uc911\ud569\ub2c8\ub2e4":227,"\uc18c\uc9c4\ub418\uae30":230,"\uc18c\ud504\ud2b8\uc6e8\uc5b4":231,"\uc18d\ub3c4":228,"\uc18d\ub3c4\ub098":228,"\uc18d\ub3c4\ub294":228,"\uc18d\ub3c4\ub97c":228,"\uc18d\ub3c4\uc774\ub2e4":228,"\uc190":231,"\uc190\uc2e4\uc5d0":231,"\uc190\uc775\ubd84\uae30":230,"\uc190\uc775\uc728":230,"\uc194\ube0c\ub808\uc778\ud640\ub529\uc2a4":230,"\uc1a1\uc2e0\ud558\uba74\ub41c\ub2e4":17,"\uc1a1\uc2e0\ud55c\ub2e4":17,"\uc218":[17,23,27,29,30,45,48,56,86,227,228,230,232],"\uc218\ub294":228,"\uc218\ub3c4":[227,228,231,232],"\uc218\ub3d9":17,"\uc218\ub3d9\uc73c\ub85c":[228,230,232],"\uc218\ub3d9\uc790\ub3d9\uc8fc\ubb38":231,"\uc218\ub7c9\uc774":[45,48],"\uc218\uc2dc\ub85c":[27,56],"\uc218\uc2dd\uc740":228,"\uc218\uc2e0":17,"\uc218\uc2e0\ub370\uc774\ud130":17,"\uc218\uc2e0\ub370\uc774\ud130\ub97c":17,"\uc218\uc2e0\ub418\ub294":17,"\uc218\uc2e0\ub418\uc9c0":17,"\uc218\uc2e0\ub41c":23,"\uc218\uc2e0\ub420":[45,48],"\uc218\uc2e0\ub420\ub54c\ub9c8\ub2e4":23,"\uc218\uc2e0\ub429\ub2c8\ub2e4":[17,23],"\uc218\uc2e0\uc2dc":[17,23],"\uc218\uc2e0\ud558\ub294":17,"\uc218\uc2e0\ud558\ub3c4\ub85d":29,"\uc218\uc2e0\ud558\uba74":17,"\uc218\uc2e0\ud558\uc9c0":29,"\uc218\uc2e0\ud55c":[17,27,56],"\uc218\uc2e0\ud560":[17,23,30],"\uc218\uc2e0\ud588\uc744\ub54c":23,"\uc218\uc775\ub960":45,"\uc218\uc815":[17,228],"\uc218\uc815\uac70\ub798\ub7c9":228,"\uc218\uc815\uace0\uac00":228,"\uc218\uc815\ub418\uc5b4\uc57c":228,"\uc218\uc815\ub418\uc9c0":228,"\uc218\uc815\ube44\uc728":[228,230,231],"\uc218\uc815\uc2dc\uac00":228,"\uc218\uc815\uc774":228,"\uc218\uc815\uc800\uac00":228,"\uc218\uc815\uc885\uac00":228,"\uc218\uc815\uc8fc\uac00":[228,231],"\uc218\uc815\uc8fc\uac00\uac00":[228,230],"\uc218\uc815\uc8fc\uac00\uad6c\ubd84":[228,230,231],"\uc218\uc815\uc8fc\uac00\ub294":228,"\uc218\uc815\uc8fc\uac00\ub77c\uba74":228,"\uc218\uc815\uc8fc\uac00\ub97c":228,"\uc218\uc815\uc8fc\uac00\ube44\uc728":228,"\uc218\uc815\uc8fc\uac00\ube44\uc728\uc5d0\uc11c":228,"\uc218\uc815\uc8fc\uac00\ube44\uc728\uc744":228,"\uc218\uc815\uc8fc\uac00\ube44\uc728\uc774":228,"\uc218\uc815\uc8fc\uac00\uc758":228,"\uc218\uc815\uc8fc\uac00\uc774\ubca4\ud2b8":[228,230,231],"\uc218\uc815\uc8fc\uac00\uc778\uac00":228,"\uc218\uc815\uc8fc\uac00\uc77c\uc790":228,"\uc218\uc815\uc8fc\uac00\uc77c\uc9c0\ub294":228,"\uc218\uc815\ud55c":228,"\uc218\uc815\ud574":232,"\uc218\uc815\ud574\uc8fc\uc5b4\uc57c":228,"\uc218\uc900\uc774\uba74":227,"\uc218\ud589":48,"\uc218\ud589\ud558\uac8c":232,"\uc218\ud589\ud558\uace0":[45,48],"\uc218\ud589\ud558\ub294":232,"\uc218\ud589\ud560":232,"\uc218\ud589\ud569\ub2c8\ub2e4":[29,227],"\uc218\ud589\ud574":227,"\uc218\ud589\ud574\uc57c":232,"\uc21c":231,"\uc21c\uac04\uc801\uc73c\ub85c":23,"\uc21c\uac04\uccb4\uacb0\ub7c9":231,"\uc21c\uc11c":17,"\uc21c\uc11c\ub294":17,"\uc21c\uc11c\ub300\ub85c":[17,227],"\uc21c\uc11c\uc5d0":17,"\uc21c\uc21c\ud788":228,"\uc21c\ucc28\uc801\uc73c\ub85c":232,"\uc22b\uc790":[17,45,48,230,231],"\uc26c\uc6b4":231,"\uc26c\uc6cc\ubcf4\uc774\ub294":228,"\uc27c\ud45c":17,"\uc27d\uac8c":[45,227,228,232],"\uc27d\uace0":231,"\uc27d\ub3c4\ub85d":17,"\uc288\ud53c\uac90\ucf54\ub9ac\uc544":230,"\uc2a4\ub9c8\ud2b8\ud3f0\uc73c\ub85c":228,"\uc2a4\ud06c\ub864\uc744":227,"\uc2a4\ud06c\ub9bd\ud2b8\uac00":232,"\uc2a4\ud06c\ub9bd\ud2b8\ub4e4\uc744":232,"\uc2a4\ud06c\ub9bd\ud2b8\ub97c":[227,232],"\uc2a4\ud0c0":17,"\uc2a4\ud0c0\uc120\ubb3c":17,"\uc2a4\ud1b1\ub85c\uc2a4":231,"\uc2a4\ud1b1\uc8fc\ubb38":231,"\uc2a4\ud2b8\ub9bc":[45,230],"\uc2a4\ud2b8\ub9bc\uacfc":230,"\uc2a4\ud2b8\ub9bc\uc73c\ub85c":232,"\uc2a4\ud2b8\ub9bc\uc744":[48,230,231,232],"\uc2a4\ud2b8\ub9bc\uc758":230,"\uc2a4\ud504\ub808\ub4dc":17,"\uc2dc":[17,230,231],"\uc2dc\uac00":[228,230,231,232],"\uc2dc\uac00\ucd1d\uc561":[230,231,232],"\uc2dc\uac00\ucd1d\uc561\ube44\uc911":[230,231,232],"\uc2dc\uac01\uc801\uc73c\ub85c":228,"\uc2dc\uac04":228,"\uc2dc\uac04\ub2f9":228,"\uc2dc\uac04\uc678":17,"\uc2dc\uac04\uc678\ub2e8\uc77c\uac00":17,"\uc2dc\uac04\uc678\ub2e8\uc77c\uac00\ub9e4\ub9e4":[17,45,152],"\uc2dc\uac04\uc678\ub2e8\uc77c\uac00\uc694\uccad":231,"\uc2dc\uac04\uc678\ub2e8\uc77c\uac00_\ud604\uc7ac\uac00":230,"\uc2dc\uac04\uc678\uc885\ubaa9\uc815\ubcf4":231,"\uc2dc\uac04\uc758":17,"\uc2dc\uacc4\uc5f4\ub85c":228,"\uc2dc\uadf8\ub110":231,"\uc2dc\uadf8\ub110\uc5d0":231,"\uc2dc\ub098\ub9ac\uc624\ub4e4\uc744":231,"\uc2dc\ub098\ub9ac\uc624\ub97c":232,"\uc2dc\ub098\ub9ac\uc624\uc5d0":[45,48,231],"\uc2dc\ub098\ub9ac\uc624\uc785\ub2c8\ub2e4":232,"\uc2dc\ub3c4\ud569\ub2c8\ub2e4":17,"\uc2dc\ub3c4\ud574\ubcf4\uc9c0":228,"\uc2dc\ub3c4\ud574\ubcfc":228,"\uc2dc\ubbac\ub808\uc774\uc158\ud558\uc5ec":232,"\uc2dc\uc138":[5,17,228,231],"\uc2dc\uc138\uac00":17,"\uc2dc\uc138\ub370\uc774\ud130\ub97c":17,"\uc2dc\uc138\ub97c":17,"\uc2dc\uc138\uc815\ubcf4":228,"\uc2dc\uc138\uc870\ud68c":22,"\uc2dc\uc138\uc870\ud68c\ub85c":17,"\uc2dc\uc138\uc870\ud68c\uc640":30,"\uc2dc\uc138\ucd94\uc774":228,"\uc2dc\uc138\ucd94\uc774\ub97c":228,"\uc2dc\uc138\ud45c\uc131":45,"\uc2dc\uc2a4\ud15c":228,"\uc2dc\uc5d0":[227,232],"\uc2dc\uc791":227,"\uc2dc\uc791\uc8fc\ubb38\ubc88\ud638":45,"\uc2dc\uc791\ud558\ub294":228,"\uc2dc\uc791\ud569\ub2c8\ub2e4":227,"\uc2dc\uc791\ud574":228,"\uc2dc\uc791\ud574\uc11c":232,"\uc2dc\uc791\ud588\ub2e4":228,"\uc2dc\uc7a5":17,"\uc2dc\uc7a5\uac00":[17,45,152,230],"\uc2dc\uc7a5\uac00fok":[17,45,152],"\uc2dc\uc7a5\uac00ioc":[17,45,152],"\uc2dc\uc7a5\uad6c\ubd84":17,"\uc2dc\uc7a5\uad6c\ubd840":17,"\uc2dc\uc7a5\uad6c\ubd841":17,"\uc2dc\uc7a5\uad6c\ubd84\uac12":17,"\uc2dc\uc7a5\uad6c\ubd84\uac12\uacfc":17,"\uc2dc\uc7a5\uad6c\ubd84\uac12\uc744":17,"\uc2dc\uc7a5\uad6c\ubd84\ub4f1\uc758":29,"\uc2dc\uc7a5\uad6c\ubd84\uc5d0":17,"\uc2dc\uc7a5\ub0b4":29,"\uc2dc\uc7a5\ubcc4":17,"\uc2dc\uc7a5\uc758":29,"\uc2dc\uc7a5\uc774":230,"\uc2dc\uc810":23,"\uc2dc\uc810\uae4c\uc9c0":228,"\uc2dc\uc810\uc5d0\uc11c":228,"\uc2dc\uc810\uc740":228,"\uc2dc\uc810\uc744":23,"\uc2dc\uc810\uc774\ub2e4":228,"\uc2dc\ud0a4\uace0":232,"\uc2dc\ud669":231,"\uc2dd\uc73c\ub85c":[45,48,228,232],"\uc2dd\uc774\uae30":232,"\uc2e0\uacbd\uc774":231,"\uc2e0\uaddc":[17,48,228,230,231,232],"\uc2e0\uaddc\ub9e4\ub3c4":[17,45,152],"\uc2e0\uaddc\ub9e4\ub9e4":17,"\uc2e0\uaddc\ub9e4\uc218":[17,45,152,230,231],"\uc2e0\uaddc\uc885\ubaa9\uc774":23,"\uc2e0\uaddc\uc8fc\ubb38\uc5d0\ub294":[17,45],"\uc2e0\ub8b0\uac00":228,"\uc2e0\ub8b0\uc131\uacfc":228,"\uc2e0\ub8b0\ud560":228,"\uc2e0\uc6a9\uac00\ub2a5":[17,29],"\uc2e0\uc6a9\uac70\ub798":17,"\uc2e0\uc6a9\uad6c\ubd84":[17,230],"\uc2e0\uc6a9\uae08\uc561":230,"\uc2e0\uc6a9\ub9e4\ub3c4":17,"\uc2e0\uc6a9\ub9e4\uc218":17,"\uc2e0\uc6a9\ube44\uc728":[230,231,232],"\uc2e0\uc6a9\uc735\uc790":231,"\uc2e0\uc6a9\uc774\uc790":230,"\uc2e0\uc6a9\uc794\uace0":17,"\uc2e0\uc6a9\uc8fc\ubb38":17,"\uc2e0\uc6a9\uc8fc\uc2dd":17,"\uc2e0\uc8fc\uc778\uc218\uad8c":[17,125,131,134],"\uc2e0\uccad\ud569\ub2c8\ub2e4":227,"\uc2e0\uccad\ud574\ub193\uc740":232,"\uc2e0\ud638\uad00\ub9ac\uc790\ud22c\uc790\uc815\ubcf4":231,"\uc2e0\ud638\ub294":23,"\uc2e0\ud638\ub97c":30,"\uc2e4":29,"\uc2e4\uac70\ub798\uc11c\ubc84":17,"\uc2e4\uac70\ub798\uc11c\ubc84\uc5d0\uc11c\ub294":45,"\uc2e4\uc11c\ubc84":17,"\uc2e4\uc2dc\uac04":[17,22,23,30,45,48,230,232],"\uc2e4\uc2dc\uac04\ub370\uc774\ud130":[230,231],"\uc2e4\uc2dc\uac04\ub370\uc774\ud130\ub97c":[17,23],"\uc2e4\uc2dc\uac04\ubaa9\ub85d":17,"\uc2e4\uc2dc\uac04\uc0c1\ud558\ud55c\uac00":231,"\uc2e4\uc2dc\uac04\uc2dc\uc138":[17,23],"\uc2e4\uc2dc\uac04\uc2dc\uc138\ub294":17,"\uc2e4\uc2dc\uac04\uc2dc\uc138\ub97c":17,"\uc2e4\uc2dc\uac04\uc73c\ub85c":23,"\uc2e4\uc2dc\uac04\uc774":17,"\uc2e4\uc2dc\uac04\uc870\ud68c":17,"\uc2e4\uc2dc\uac04\uc99d\uac70\uae08":231,"\uc2e4\uc2dc\uac04log":231,"\uc2e4\uc804":231,"\uc2e4\uc804\uc5d0":228,"\uc2e4\uc81c":[45,227,228,230,232],"\uc2e4\uc81c\ub85c":[231,232],"\uc2e4\ud328":[17,22,23,86],"\uc2e4\ud328\uc785\ub2c8\ub2e4":17,"\uc2e4\ud328\ud558\uac8c":17,"\uc2e4\ud328\ud558\ub294":17,"\uc2e4\ud328\ud558\uba74":17,"\uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4":86,"\uc2e4\ud589":[227,228,230],"\uc2e4\ud589\ub418\ub294":232,"\uc2e4\ud589\ub418\uc5b4\uc57c":232,"\uc2e4\ud589\ub420":48,"\uc2e4\ud589\uc2dc":[227,230,232],"\uc2e4\ud589\uc2dc\ucf1c":48,"\uc2e4\ud589\uc2dc\ucf1c\ub450\uc9c0":228,"\uc2e4\ud589\ud558\uac8c":232,"\uc2e4\ud589\ud558\ub294":232,"\uc2e4\ud589\ud558\uba74":227,"\uc2e4\ud589\ud558\uc5ec":227,"\uc2e4\ud589\ud558\uc790":228,"\uc2e4\ud589\ud55c\ub2e4":17,"\uc2e4\ud589\ud560":232,"\uc2e4\ud589\ud569\ub2c8\ub2e4":[29,227],"\uc2e4\ud589\ud588\uc744":232,"\uc2e4\ud5d8\uc801\uc73c\ub85c":232,"\uc2eb\ub2e4":228,"\uc2eb\uc740\ub370":228,"\uc2ec\ucc9c":231,"\uc2f1\uae00\ub370\uc774\ud130":[230,232],"\uc2f6\ub2e4":228,"\uc2f6\ub2e4\uba74":230,"\uc2f6\uc2b5\ub2c8\ub2e4":5,"\uc2f6\uc73c\uba74":17,"\uc2f6\uc740":[227,228,230],"\uc2f6\uc744\ub54c":48,"\uc2f6\uc9c0\ub9cc":228,"\uc30d\uc73c\ub85c":17,"\uc30d\uc744":17,"\uc384\ud0c0":[230,231],"\uc464\uc154":231,"\uc4f0\uae30":228,"\uc4f0\ub294":227,"\uc4f0\ub358":228,"\uc4f0\ub828\ub2e4":228,"\uc4f0\uc600\uc2b5\ub2c8\ub2e4":231,"\uc4f0\uc774\ub294":230,"\uc528\uc564\ud22c\uc2a4\uc131\uc9c4":230,"\uc528\uc820":230,"\uc544\ub2c8\uac70\ub098":29,"\uc544\ub2c8\uae30":230,"\uc544\ub2c8\ub2e4":230,"\uc544\ub2c8\ub77c":[228,230],"\uc544\ub2c8\ub77c\uba74":[228,232],"\uc544\ub2c8\uba74":[17,227,228,230,231],"\uc544\ub2cc":[17,29,45,48,228,231,232],"\uc544\ub2cc\uac00":231,"\uc544\ub2d0":228,"\uc544\ub2d0\uc9c0":228,"\uc544\ub798":[4,29,227,228,230,231,232],"\uc544\ub798\uac00":17,"\uc544\ub798\ub294":[228,232],"\uc544\ub798\ub3c4":228,"\uc544\ub798\uc5d0":[227,232],"\uc544\ub798\uc5d0\uc11c":230,"\uc544\ub798\uc640":[17,228,230,231,232],"\uc544\ub798\uc758":[227,228,232],"\uc544\ub798\ucc98\ub7fc":[228,230,232],"\uc544\ub9c8\ub3c4":[17,228],"\uc544\ubb34":232,"\uc544\uc26c\uc6b4":228,"\uc544\uc608":[228,232],"\uc544\uc774\ub514":[17,230,232],"\uc544\uc774\ub514\ub85c":17,"\uc544\uc774\ub514\ub97c":232,"\uc544\uc774\ub514\uc5b4\ub97c":228,"\uc544\uc774\ub514\uc5b4\uc640":228,"\uc544\uc774\ub514_newsaveindex":17,"\uc544\uc774\ucf58\uc740":232,"\uc544\uc774\ucf58\uc744":232,"\uc544\uc774\ucf58\uc758":232,"\uc544\uc774\ucf58\uc774":232,"\uc544\uc774\ud15c":[17,23],"\uc544\uc774\ud15c\uba85":17,"\uc544\uc774\ud15c\uc758":17,"\uc544\uc774\ud53c":86,"\uc544\uc9c1":228,"\uc544\uc9c1\uae4c\uc9c0\ub294":228,"\uc544\ud30c\uc11c":228,"\uc544\ud504\uac8c":231,"\uc548\ub0b4":228,"\uc548\ub0b4\ub97c":228,"\uc548\ub418\ub294":17,"\uc548\ub429\ub2c8\ub2e4":[27,56],"\uc548\ub9de\uac70\ub098":17,"\uc548\uc5d0\uc11c":17,"\uc548\uc815\uc131\uc5d0":48,"\uc548\uc815\uc801\uc778":227,"\uc548\ud558\ub294":228,"\uc54a\uac8c":230,"\uc54a\uace0":[45,48,228,232],"\uc54a\uae30":[45,48,228],"\uc54a\ub098":228,"\uc54a\ub294":[17,23,45,48,228,230],"\uc54a\ub294\ub2e4":228,"\uc54a\ub2e4":228,"\uc54a\ub2e4\ub294":228,"\uc54a\ub2e4\uba74":[29,45,48,227,228],"\uc54a\ub354\ub77c\ub3c4":231,"\uc54a\ub3c4\ub85d":[29,230,232],"\uc54a\uc2b5\ub2c8\ub2e4":[17,29,45,86,227,231,232],"\uc54a\uc544\ub3c4":[227,228],"\uc54a\uc558\ub2e4":228,"\uc54a\uc558\ub2e4\uba74":[29,45,228],"\uc54a\uc558\uc2b5\ub2c8\ub2e4":231,"\uc54a\uc73c\uba74\uc11c\ub3c4":231,"\uc54a\uc740":[17,29,228,230],"\uc54a\uc744":[17,45,48,232],"\uc54a\uc744\uae4c":228,"\uc54a\uc744\uc9c0":228,"\uc54a\uc74c":17,"\uc54a\uc9c0\ub9cc":228,"\uc54c":[17,228,231],"\uc54c\uac8c":228,"\uc54c\uace0":[5,228,231],"\uc54c\ub78c":231,"\uc54c\ub824\uc8fc\uae38":228,"\uc54c\ub824\uc8fc\uc9c0\ub294":228,"\uc54c\ub824\uc900\ub2e4":23,"\uc54c\ub824\uc90d\ub2c8\ub2e4":[17,27,56],"\uc54c\ub9de\uac8c":232,"\uc54c\ub9de\ub294":228,"\uc54c\ub9de\uc2b5\ub2c8\ub2e4":231,"\uc54c\ub9de\uc740":[45,48],"\uc54c\uc544\ub0c8\ub2e4":228,"\uc54c\uc544\ubcf4\uae30\uc5d0":227,"\uc54c\uc544\uc11c":232,"\uc54c\uc544\ucc4c":231,"\uc54c\uc9c0":231,"\uc54c\ud30c":231,"\uc555\ub3c4\uc801\uc73c\ub85c":228,"\uc55e\uc11c":[45,48,227,228,230,231],"\uc55e\uc120":[48,228,230,232],"\uc55e\uc5d0\uc11c\ub294":231,"\uc55e\uc758":[227,228,230,231],"\uc560\ucd08\uc5d0":231,"\uc561\uba74":228,"\uc561\uba74\uac00":[230,231,232],"\uc561\uba74\uac00\ub2e8\uc704":[230,231,232],"\uc561\uba74\ubd84\ud560":[17,29],"\uc57c\ud6c4\uc758":228,"\uc57d\uac04":228,"\uc57d\uac04\uc740":228,"\uc57d\uac04\uc758":[228,230],"\uc57d\uac04\uc774\ub098\ub9c8":228,"\uc5b4\ub290":[228,231],"\uc5b4\ub290\uc815\ub3c4":228,"\uc5b4\ub514\uae4c\uc9c0\uc778\uc9c0":228,"\uc5b4\ub514\uc11c\ub4e0":228,"\uc5b4\ub5a0\ud55c":231,"\uc5b4\ub5a4":232,"\uc5b4\ub5bb\uac8c":[228,231,232],"\uc5b4\ub835\uac8c":228,"\uc5b4\ub835\uc2b5\ub2c8\ub2e4":231,"\uc5b4\ub835\uc9c0":228,"\uc5b4\ucc0c":228,"\uc5b4\ud50c\ub9ac\ucf00\uc774\uc158":232,"\uc5b4\ud50c\ub9ac\ucf00\uc774\uc158\uc5d0":232,"\uc5b4\ud50c\ub9ac\ucf00\uc774\uc158\uc744":231,"\uc5b8\uae09\ub41c":228,"\uc5b8\uae09\ud55c":230,"\uc5b8\uc5b4":231,"\uc5b8\uc5b4\ub4e4\ub85c":231,"\uc5b8\uc5b4\ub4e4\uc5d0":231,"\uc5b8\uc81c\ub4e0\uc9c0":228,"\uc5bb\ub294":17,"\uc5bb\uc5b4\uc624\ub294":17,"\uc5bb\uc5b4\uc62c":23,"\uc5bb\uc740":17,"\uc5bb\uc744":228,"\uc5bb\uc744\ub54c":17,"\uc5bb\uc744\uc218":[17,23],"\uc5bd\ub9e4\uc77c":231,"\uc5c4\ubc00\ud558\uac8c":228,"\uc5c5\uadf8\ub808\uc774\ub4dc":29,"\uc5c5\ub370\uc774\ud2b8":[228,231,232],"\uc5c5\ub370\uc774\ud2b8\uac00":[228,232],"\uc5c5\ub370\uc774\ud2b8\ub294":228,"\uc5c5\ub370\uc774\ud2b8\ub85c":232,"\uc5c5\ub370\uc774\ud2b8\ub97c":[228,232],"\uc5c5\ub370\uc774\ud2b8\uc2dc":228,"\uc5c5\ub370\uc774\ud2b8\uc758":227,"\uc5c5\ubb34\uad6c\ubd84":230,"\uc5c5\ubb34\ub294":228,"\uc5c5\uc885\uad6c\ubd84":17,"\uc5c5\uc885\uad6c\ubd84\uac12\uc744":17,"\uc5c5\uc885\ub4f1\ub77d":231,"\uc5c5\uc885\uba85":17,"\uc5c5\uc885\uba85\uc774":17,"\uc5c5\uc885\uc774\ub984":17,"\uc5c5\uc885\uc9c0\uc218":231,"\uc5c5\uc885\ucf54\ub4dc":[17,29],"\uc5c5\uc885\ucf54\ub4dc\ub294":17,"\uc5c5\uc885\ucf54\ub4dc\ubaa9\ub85d":17,"\uc5c5\uc885\ucf54\ub4dc\uc758":29,"\uc5c5\uc885\ucf54\ub4dc\uc785\ub825":17,"\uc5c6\uac70\ub098":17,"\uc5c6\uac8c":231,"\uc5c6\uace0":[17,232],"\uc5c6\uae30":228,"\uc5c6\ub294":[17,29,228],"\uc5c6\ub294\ub370":227,"\uc5c6\ub294\uc9c0":227,"\uc5c6\ub2e4":228,"\uc5c6\uc2b5\ub2c8\ub2e4":[17,23,30,86,227,231,232],"\uc5c6\uc5b4":228,"\uc5c6\uc5b4\uc11c":228,"\uc5c6\uc5b4\uc84c\uc2b5\ub2c8\ub2e4":231,"\uc5c6\uc73c\ub9ac\ub77c":231,"\uc5c6\uc73c\uba74":[227,228],"\uc5c6\uc73c\ubbc0\ub85c":231,"\uc5c6\uc744\uae4c":228,"\uc5c6\uc744\uae4c\ub97c":231,"\uc5c6\uc74c":[17,22,23],"\uc5c6\uc774":[48,228,231,232],"\uc5c6\uc9c0\ub9cc":231,"\uc5d0":[17,23,45,48,227,230,231,232],"\uc5d0\ub3c4":230,"\uc5d0\ub7ec":17,"\uc5d0\ub7ec\ub294":23,"\uc5d0\ub7ec\ub97c":[45,48],"\uc5d0\ub7ec\uc785\ub2c8\ub2e4":17,"\uc5d0\ub7ec\ucf54\ub4dc":[17,23,29],"\uc5d0\ub7ec\ucf54\ub4dc\uc5d0":231,"\uc5d0\uc11c":[45,227,228,231,232],"\uc5d0\uc11c\ub294":[17,45,48,228,231,232],"\uc5d0\uc11c\ub3c4":232,"\uc5d0\uc11c\ub9cc":29,"\uc5d0\uc2a4\ub514\ubc14\uc774\uc624\uc13c\uc11c":230,"\uc5d0\uc2a4\uc5d0\ud504\uc5d0\uc774":230,"\uc5d0\uc774\ub9ac\uce20":230,"\uc5d1\uc138\uc2a4\ubc14\uc774\uc624":[230,231],"\uc5d1\uc140\ud30c\uc77c\ub85c":228,"\uc5d1\uc140\ud30c\uc77c\uc744":228,"\uc5d4\uc120\ubb3c":17,"\uc5d4\uc9c0\ub2c8\uc5b4\ub9c1\uc744":228,"\uc5d4\uc9c0\ub2c8\uc5b4\ub9c1\uc774":228,"\uc5d4\ud2b8\ub9ac\ud3ec\uc778\ud2b8\uc758":230,"\uc5ec\uae30\uc11c":[227,228,230,231,232],"\uc5ec\uae30\uc11c\ub294":[227,228,230,231],"\uc5ec\uae30\uc11c\uc758":232,"\uc5ec\uae30\uc5d0":23,"\uc5ec\uae30\uc5d0\ub294":227,"\uc5ec\uae30\uc800\uae30":228,"\uc5ec\ub7ec":[17,45,227,228,232],"\uc5ec\ub7ec\ubd84\uc758":227,"\uc5ec\ubd80":[17,23,29,232],"\uc5ec\ubd80\ub97c":[17,23,29,45],"\uc5ec\ubd80\uc5d0":17,"\uc5ec\uc804\ud788":231,"\uc5ed\uc0b0\ud55c":228,"\uc5ed\uc0b0\ud574":228,"\uc5ed\uc21c":45,"\uc5ed\uc2dc":[228,230],"\uc5ed\uc2dc\ub098":228,"\uc5ed\uc73c\ub85c":228,"\uc5f0\uacb0":[17,45,48],"\uc5f0\uacb0\uae4c\uc9c0\ub294":227,"\uc5f0\uacb0\ub41c":17,"\uc5f0\uacb0\uc548\ub428":17,"\uc5f0\uacb0\uc744":[45,48],"\uc5f0\uacb0\uc885\ub8cc":22,"\uc5f0\uacb0\ud558\uc5ec":227,"\uc5f0\uacb0\ud55c":17,"\uc5f0\ub3c44\uc790\ub9ac":45,"\uc5f0\uc18d":17,"\uc5f0\uc18d\uc870\ud68c":[17,23,228],"\uc5f0\uc18d\uc870\ud68c\uac00":[17,45,48],"\uc5f0\uc18d\uc870\ud68c\ub97c":17,"\uc5f0\uc774\uc5b4":232,"\uc5f0\uc911\ucd5c\uace0":[230,231,232],"\uc5f0\uc911\ucd5c\uc800":[230,231,232],"\uc5f0\ud734\uac00":228,"\uc5f4\ub824":230,"\uc5f4\ub824\uc788\ub294":230,"\uc5f4\uc5b4":230,"\uc5f4\uc5b4\uc11c":231,"\uc601\uc5c5\uc774\uc775":[230,231,232],"\uc601\uc5c5\uc77c\uacfc":228,"\uc601\uc5c5\uc77c\uc5d0\uc11c":228,"\uc601\uc5c5\uc77c\uc758":228,"\uc601\uc5ed\uc73c\ub85c":228,"\uc601\uc6c5\ubb38":[228,230],"\uc601\uc6c5\ubb384":17,"\uc601\uc6c5\ubb38\uc5d0\uc11c":17,"\uc601\uc6d0\ubb34\uc5ed":230,"\uc601\uc6d0\ubb34\uc5ed\ud640\ub529\uc2a4":230,"\uc601\ud5a5\uc73c\ub85c":228,"\uc608\ub85c":231,"\uc608\ub97c":[17,228,230,231,232],"\uc608\uc0c1\uac00\uaca9":228,"\uc608\uc0c1\uc5c5\uc885\uc9c0\uc218":231,"\uc608\uc0c1\uccb4\uacb0\uac00":[230,231,232],"\uc608\uc0c1\uccb4\uacb0\ub7c9":230,"\uc608\uc0c1\uccb4\uacb0\uc218\ub7c9":[230,231,232],"\uc608\uc218\uae08":[45,230,231],"\uc608\uc2dc":[23,230,232],"\uc608\uc2dc\uac00":232,"\uc608\uc2dc\ub294":232,"\uc608\uc2dc\ub4e4\uc5d0\uc11c":230,"\uc608\uc2dc\ub4e4\uc740":231,"\uc608\uc2dc\ub4e4\uc744":231,"\uc608\uc2dc\ub85c":[230,232],"\uc608\uc2dc\ub97c":[228,232],"\uc608\uc2dc\uc5d0\uc11c\ub294":[17,230],"\uc608\uc2dc\uc5d0\uc11c\uc640":230,"\uc608\uc2dc\uc640":227,"\uc608\uc2dc\uc758":230,"\uc608\uc2dc\uc9c0\ub9cc":17,"\uc624\ub294":227,"\uc624\ub69c\uae30":230,"\uc624\ub798\ub41c":228,"\uc624\ub958":[22,86],"\uc624\ub958\uac00":227,"\uc624\ub958\uad00\ub828\ucc98\ub9ac\ub97c":[27,56],"\uc624\ub958\ub85c":228,"\uc624\ub9ac\uc628":230,"\uc624\ub9ac\uc628\ud640\ub529\uc2a4":[230,231],"\uc624\ubc84\ud50c\ub85c\uc6b0":29,"\uc624\ube0c\uc81d\ud2b8":5,"\uc624\uc9c1":17,"\uc624\ud574\uc18c\uc9c0\uac00":17,"\uc624\ud788\ub824":228,"\uc628\ub2e4":17,"\uc62c\ubc14\ub978":228,"\uc635\uc158":[17,232],"\uc635\uc158\ub3c4":227,"\uc635\uc158\ub4e4":231,"\uc635\uc158\ub4f1\uc5d0":227,"\uc635\uc158\ub9e4\ub3c4\uc8fc\ubb38\uc99d\uac70\uae08\ud604\ud669\uc694\uccad":231,"\uc635\uc158\uc2dc\uc138":231,"\uc635\uc158\uc744":[227,232],"\uc635\uc158\uc774\ub860\uac00":231,"\uc635\uc158\uc911":231,"\uc635\uc158\ud638\uac00\uc794\ub7c9":231,"\uc640":[17,23,45,48,228,231,232],"\uc640\uc758":227,"\uc644\ub8cc":232,"\uc644\ub8cc\ub418\uba74":232,"\uc644\ub8cc\ub418\uc5c8\uc2b5\ub2c8\ub2e4":[23,227],"\uc644\ub8cc\ub418\uc5c8\uc73c\uba74":227,"\uc644\ub8cc\ub41c":[45,48],"\uc644\ub8cc\ub420":48,"\uc644\ub8cc\ud558\uba74":48,"\uc644\ub8cc\ud574\uc11c":230,"\uc644\uc804\ud788":17,"\uc65c\uace1\uc2dc\ud0ac":228,"\uc660\uc9c0":228,"\uc678":17,"\uc678\ubd80":[228,231],"\uc678\ubd80\ub9c1\ud06c":232,"\uc678\ubd80\uc5d0":230,"\uc678\uc778\uc18c\uc9c4\ub960":[230,231,232],"\uc678\uc801\uc73c\ub85c":231,"\uc694\uad6c\uc0ac\ud56d\uacfc":231,"\uc694\uad6c\uc0ac\ud56d\uc5d0":231,"\uc694\uc18c\ub4e4\uc744":231,"\uc694\uc998\uc740":228,"\uc694\uccad":[5,17,30,45,48,228,230],"\uc694\uccad\uba85":[17,45],"\uc694\uccad\ubc1b\uc740":[45,48],"\uc694\uccad\ubd80\ud130":231,"\uc694\uccad\uc2dc":48,"\uc694\uccad\uc2dc\uc5d0":228,"\uc694\uccad\uc5d0":[23,45,48,230,231],"\uc694\uccad\uc5d0\ub300\ud55c":23,"\uc694\uccad\uc5d0\uc11c":228,"\uc694\uccad\uc73c\ub85c":23,"\uc694\uccad\uc740":30,"\uc694\uccad\uc744":[17,48,227,228,231],"\uc694\uccad\uc790\uac00":231,"\uc694\uccad\uc790\uce21\uc5d0":231,"\uc694\uccad\uc804\ubb38":17,"\uc694\uccad\ud558\uace0":[45,230],"\uc694\uccad\ud558\uae30":228,"\uc694\uccad\ud558\ub294":[17,228],"\uc694\uccad\ud558\uba74":228,"\uc694\uccad\ud55c":[17,231],"\uc694\uccad\ud55c\ub2e4":228,"\uc694\uccad\ud560":[48,232],"\uc694\uccad\ud560\ub54c":17,"\uc694\uccad\ud569\ub2c8\ub2e4":17,"\uc694\uccad\ud574":[48,228],"\uc694\uccad\ud588\ub358":23,"\uc6a9\ub3c4\ub85c":23,"\uc6a9\ub3c4\uc5d0":17,"\uc6b0\ub7c9\uc8fc":[230,231],"\uc6b0\ub824\ub418\ub294":231,"\uc6b0\ub824\ud574":228,"\uc6b0\ub824\ud588\ub358":231,"\uc6b0\ub9ac\ub098\ub77c\uc758":228,"\uc6b0\ub9ac\uc190\uc5d0\ud504\uc564\uc9c0":230,"\uc6b0\ub9ac\uc5d0\uac8c":228,"\uc6b0\uc120":231,"\uc6b0\uc120\ub9e4\ub3c4\uac74\uc218":230,"\uc6b0\uc120\ub9e4\ub3c4\uc794\ub7c9":230,"\uc6b0\uc120\ub9e4\uc218\uac74\uc218":230,"\uc6b0\uc120\ub9e4\uc218\uc794\ub7c9":230,"\uc6b0\uce21":232,"\uc6b0\uce21\uc0c1\ub2e8\uc758":228,"\uc6b0\uce21\ud558\ub2e8\uc5d0":232,"\uc6b0\ud074\ub9ad":228,"\uc6b0\ud074\ub9ad\ud558\ub294":232,"\uc6d0":[230,231,232],"\uc6d0\ub798":[17,228],"\uc6d0\ub798\uc758":228,"\uc6d0\ubcf8\uc8fc\uac00":228,"\uc6d0\uc8fc\ubb38":23,"\uc6d0\uc8fc\ubb38\ubc88\ud638":[17,45,230,231],"\uc6d0\ud558\ub294":228,"\uc6d4":45,"\uc6d4\ub2e8\uc704":228,"\uc6d4\ubb3c":17,"\uc6d4\ubb3c\uac04":17,"\uc6d4\ubb3c\ub9cc":17,"\uc6d4\ubb3c\uc758":17,"\uc6d4\ubb3c\uc815\ubcf4\ub97c":17,"\uc6f9":228,"\uc6f9\uc0ac\uc774\ud2b8":228,"\uc6f9\uc0ac\uc774\ud2b8\uc758":228,"\uc6f9\uc820":230,"\uc6f9\ud398\uc774\uc9c0\uc640":228,"\uc704":17,"\uc704\uc544\ub798\uc758":228,"\uc704\uc5d0\uc11c":[228,230,231],"\uc704\uc640":[228,231],"\uc704\uc758":[227,228,230,231,232],"\uc704\ucc98\ub7fc":232,"\uc704\uce58\ud55c":227,"\uc704\ud0a4\uc5d0\uc11c\ub294":232,"\uc704\ud558\uc5ec":232,"\uc704\ud55c":[28,29,45,48,227,232],"\uc704\ud574":[45,227,228,230,231],"\uc704\ud574\uc11c":[227,230],"\uc704\ud574\uc11c\ub294":[17,227,228,230,231,232],"\uc708\ub3c4\uc6b0\ub97c":17,"\uc719\uc785\ud478\ub4dc":230,"\uc720\uac00":228,"\uc720\uac00\uc99d\uad8c":228,"\uc720\ub2c8\ub4dc":230,"\uc720\ub2c8\ubc84\uc15c\ud55c":29,"\uc720\ub85c\uc120\ubb3c":17,"\uc720\ubb34":23,"\uc720\uc5f0\ud558\uac8c":[230,231],"\uc720\uc6a9\ud558\uac8c":228,"\uc720\uc6a9\ud558\uac8c\ub054":231,"\uc720\uc6a9\ud560":[45,48],"\uc720\uc758\ubbf8\ud55c":228,"\uc720\uc758\ubbf8\ud568":[230,231],"\uc720\uc9c0\ud558\uace0":17,"\uc720\uc9c0\ud558\uba74\uc11c":48,"\uc720\uc9c0\ud560":232,"\uc720\ucd94\ud574\ubcfc":228,"\uc720\ud1b5\ube44\uc728":[230,231,232],"\uc720\ud1b5\uc8fc\uc2dd":[230,231,232],"\uc720\ud615":[17,45],"\uc720\ud615\ud654\uac00":232,"\uc720\ud6a8\ud558\uc9c0":228,"\uc735\uc790\uc0c1\ud658":17,"\uc735\uc790\ud569":17,"\uc735\uc790\ud569\uc774\uba74":17,"\uc73c\ub85c":[17,23,227,228,231,232],"\uc740":[30,227,228,232],"\uc744":[17,29,45,48,227,228,230,231,232],"\uc74c\uc218":23,"\uc74c\uc218\ub97c":17,"\uc751\ub2f5":[23,45,48],"\uc751\ub2f5\ub4e4\ub9cc":231,"\uc751\ub2f5\ubc1b\ub294":17,"\uc751\ub2f5\ucc98\ub9ac\uac00":[45,48],"\uc751\ub2f5\ud615\ud0dc\ub85c":[45,48],"\uc758":[17,23,29,45,48,227,228,230,232],"\uc758\ub3c4":231,"\uc758\ubbf8":231,"\uc758\ubbf8\uac00":228,"\uc758\ubbf8\ub2e4":228,"\uc758\ubbf8\uc5c6\uc74c":230,"\uc758\ubbf8\ud569\ub2c8\ub2e4":231,"\uc758\uc2ec\ud574\ubcfc":228,"\uc758\uc874\uc131\uc911\uc5d0":227,"\uc758\ud574":232,"\uc774":[17,23,27,45,48,56,227,228,231,232],"\uc774\uac74":228,"\uc774\uac83\ub4e4\uc744":231,"\uc774\uac83\ubcf4\ub2e4":232,"\uc774\uac83\uc740":[228,231],"\uc774\uac83\uc744":[228,232],"\uc774\uac83\uc800\uac83":228,"\uc774\uac8c":231,"\uc774\uae30":227,"\uc774\ub098":231,"\uc774\ub2e4":[17,228],"\uc774\ub7ec\ud55c":[228,231],"\uc774\ub7f0":[231,232],"\uc774\ub807\uac8c":[17,232],"\uc774\ub825\uc774":228,"\uc774\ub85c":231,"\uc774\ub860\uac00":[230,231],"\uc774\ub97c":[228,231],"\uc774\ub984":[17,23,29,48],"\uc774\ub984\uacfc":[17,45,48],"\uc774\ub984\uc5d0":[230,231],"\uc774\ub984\uc5d0\uc11c":227,"\uc774\ub984\uc73c\ub85c":[17,228,230,231],"\uc774\ub984\uc744":[17,29,230],"\uc774\ub984\uc758":232,"\uc774\ub984\uc774":17,"\uc774\ub984\uc774\ub2e4":23,"\uc774\ubbc0\ub85c":232,"\uc774\ubbf8":[29,45,228,230,231,232],"\uc774\ubc88\uc5d0\ub294":228,"\uc774\ubca4\ud2b8":[17,23,27,29,45,48,56,230,232],"\uc774\ubca4\ud2b8\uac00":[17,45,48,231,232],"\uc774\ubca4\ud2b8\ub0b4\ubd80\uc5d0\uc11c":23,"\uc774\ubca4\ud2b8\ub294":230,"\uc774\ubca4\ud2b8\ub4e4\ub9cc":48,"\uc774\ubca4\ud2b8\ub4e4\uc744":45,"\uc774\ubca4\ud2b8\ub85c":[23,45,48,230],"\uc774\ubca4\ud2b8\ub8e8\ud504":232,"\uc774\ubca4\ud2b8\ub97c":[45,48,228,230,232],"\uc774\ubca4\ud2b8\ub9c8\ub2e4":230,"\uc774\ubca4\ud2b8\ubcf4\ub2e4":[45,48],"\uc774\ubca4\ud2b8\uc5d0":[17,48,231],"\uc774\ubca4\ud2b8\uc5d0\uc11c":[17,45,48],"\uc774\ubca4\ud2b8\uc758":[17,48],"\uc774\ubca4\ud2b8\uc778":17,"\uc774\ubca4\ud2b8\uc785\ub2c8\ub2e4":23,"\uc774\uc0c1":[17,23,29,45,48,228,231],"\uc774\uc0c1\uc744":228,"\uc774\uc0c1\ud558\uac8c":228,"\uc774\uc288":[228,231],"\uc774\uc288\ub2e4":228,"\uc774\uc288\uc640":231,"\uc774\uc288\uc774\uae30":227,"\uc774\uc57c\uae30\ub97c":228,"\uc774\uc57c\uae30\ud558\uace0":228,"\uc774\uc57c\uae30\ud588\uc9c0\ub9cc":231,"\uc774\uc5b4\uc11c":[230,232],"\uc774\uc5b4\uc838\uc11c":228,"\uc774\uc5d0":[17,228],"\uc774\uc678\uc5d0":[45,48,228],"\uc774\uc678\uc758":17,"\uc774\uc6a9\ud558\ub294":231,"\uc774\uc6a9\ud558\uc5ec":17,"\uc774\uc6a9\ud55c":17,"\uc774\uc6a9\ud574\uc11c":[17,23],"\uc774\uc720\ub294":228,"\uc774\uc720\ub4e4\ub85c":231,"\uc774\uc720\ub85c":17,"\uc774\uc804":17,"\uc774\uc804\uc5d0":[29,45,48],"\uc774\uc804\uc5d0\ub3c4":230,"\uc774\uc804\uc758":227,"\uc774\uc810":231,"\uc774\uc810\uc744":228,"\uc774\uc810\uc774":231,"\uc774\uc81c":[227,228,232],"\uc774\uc9c0\ub9cc":[29,228],"\uc774\ucc98\ub7fc":231,"\uc774\ud0c8":23,"\uc774\ud0c8\ub418\ub294":23,"\uc774\ud0c8\ub41c":23,"\uc774\ud0c8\ub420\ub54c":23,"\uc774\ud0c8\ud560\ub54c\ub9c8\ub2e4":230,"\uc774\ud558\ub97c":228,"\uc774\ud558\uc758":228,"\uc774\ud574\uc5d0":232,"\uc774\ud574\ud558\uace0":232,"\uc774\ud6c4":[17,29,45,48,227,228,230,231,232],"\uc774\ud6c4\ub294":231,"\uc774\ud6c4\ubd80\ud130":17,"\uc774\ud6c4\ubd80\ud130\ub294":232,"\uc774\ud6c4\uc5d0":[227,230,232],"\uc774\ud6c4\uc5d0\ub294":[45,48],"\uc774\ud6c4\uc758":232,"\uc775\uc219\ud558\uc9c0":231,"\uc778":230,"\uc778\ub371\uc2a4":[17,23],"\uc778\ubc84\uc2a4":231,"\uc778\uc120\uc774\uc5d4\ud2f0":230,"\uc778\uc2a4\ud134\uc2a4":48,"\uc778\uc704\uc801\uc73c\ub85c":228,"\uc778\uc790":17,"\uc778\uc790\uac12":23,"\uc778\uc790\uac12\uc73c\ub85c":17,"\uc778\uc790\uac12\uc744":17,"\uc778\uc790\ub85c":[17,29,230,231],"\uc778\uc790\ub85c\uc11c":231,"\uc778\uc790\ub97c":[48,231],"\uc778\uc99d\uc815\ubcf4\ub97c":228,"\uc778\ud0d1\uc2a4":230,"\uc778\ud130\ub137":231,"\uc778\ud130\ub799\ud2f0\ube0c\ud558\uac8c":231,"\uc778\ud130\ud398\uc774\uc2a4\ub294":231,"\uc778\ud130\ud398\uc774\uc2a4\ub97c":[29,230,231],"\uc778\ud130\ud504\ub9ac\ud130\uc5d0\uc11c":227,"\uc778\ud55c":[17,228],"\uc778\ud574":[228,232],"\uc77c":45,"\uc77c\ub2e8":228,"\uc77c\ub54c\ub294":17,"\uc77c\ub828\uc758":228,"\uc77c\ubc18":228,"\uc77c\ubc18\uc2e0\ud638":231,"\uc77c\ubc18\uc801\uc73c\ub85c":[17,227,231],"\uc77c\ubc18\uc801\uc73c\ub85c\ub294":[45,48,231],"\uc77c\ubc18\uc801\uc73c\ub860":231,"\uc77c\ubc18\uc801\uc778":[17,45,48,227,228],"\uc77c\ubc18\uc870\uac74":230,"\uc77c\ubc18\uc870\ud68c":[17,45],"\uc77c\ubc18\uc8fc\uac00":231,"\uc77c\ubc18\uc8fc\ubb38\ucc98\ub7fc":17,"\uc77c\ubcc4":228,"\uc77c\ubcc4\ub9e4\ub9e4\uc815\ubcf4":228,"\uc77c\ubd09":[228,231],"\uc77c\ubd09\ubcf4\ub2e4":228,"\uc77c\ubd80":17,"\uc77c\uc73c\ud0ac":227,"\uc77c\uc774":228,"\uc77c\uc77c\uc774":[228,231],"\uc77c\uc790":[228,230,231],"\uc77c\uc790\uae4c\uc9c0\uc758":228,"\uc77c\uc790\ubcc4":228,"\uc77c\uc790\uc5d0":228,"\uc77c\ucc28\uc801\uc73c\ub85c":[29,231],"\uc77d\uae30":[230,231],"\uc77d\uc5b4":[45,48],"\uc77d\uc5b4\uc640":231,"\uc77d\uc744":[230,231],"\uc784\uc2dc\ub85c":17,"\uc784\uc2dc\ud3f4\ub354\uc5d0":227,"\uc784\uc758\ub85c":[17,230,231],"\uc784\uc758\uc5f0\uc7a5\uc815\ubcf4":231,"\uc784\uc758\uc758":[45,48,230,231],"\uc785\ub2c8\ub2e4":[17,28,29,45,48],"\uc785\ub825":[17,45,230,232],"\uc785\ub825\uac12":[22,29,231],"\uc785\ub825\uac12\ub4e4\uc744":17,"\uc785\ub825\uac12\uc744":230,"\uc785\ub825\uac12\uc744\ub85c":29,"\uc785\ub825\uacfc":231,"\uc785\ub825\ub41c":17,"\uc785\ub825\uc2dc":[17,29],"\uc785\ub825\uc744":[23,232],"\uc785\ub825\uc774":232,"\uc785\ub825\ucc3d":[17,227,232],"\uc785\ub825\ud558\uac70\ub098":231,"\uc785\ub825\ud558\uace0":[17,232],"\uc785\ub825\ud558\uae30\uc5d0":227,"\uc785\ub825\ud558\ub3c4\ub85d":231,"\uc785\ub825\ud558\uc2ed\uc2dc\uc624":86,"\uc785\ub825\ud558\uc5ec":231,"\uc785\ub825\ud558\uc9c0":232,"\uc785\ub825\ud55c":[17,29],"\uc785\ub825\ud55c\ub2e4":17,"\uc785\ub825\ud569\ub2c8\ub2e4":[17,45],"\uc785\ub825\ud574":[227,228,230],"\uc785\ub825\ud574\uc90d\ub2c8\ub2e4":227,"\uc785\uc7a5\uc5d0\uc11c\ub294":231,"\uc785\uc7a5\uc774\ub77c\uba74":228,"\uc788\uac8c":231,"\uc788\uaca0\ub2e4":228,"\uc788\uaca0\ub2e4\uace0":228,"\uc788\uaca0\uc8e0":231,"\uc788\uaca0\uc9c0\ub9cc":[227,228,232],"\uc788\uace0":[48,228,231],"\uc788\uae30":[230,231,232],"\uc788\uae34":228,"\uc788\ub294":[17,29,45,48,227,228,230,231,232],"\uc788\ub294\uac00":228,"\uc788\ub294\uac70":228,"\uc788\ub294\uac74":228,"\uc788\ub294\uac8c":228,"\uc788\ub294\ub370":[17,228],"\uc788\ub294\ub370\uc694":[231,232],"\uc788\ub294\uc9c0":[230,232],"\uc788\ub2e4":[17,228,230],"\uc788\ub2e4\uace0":228,"\uc788\ub2e4\ub294":[227,228,231,232],"\uc788\ub2e4\ub294\uac78":228,"\uc788\ub2e4\uba74":[228,231],"\uc788\ub358":[17,227,228],"\uc788\ub3c4\ub85d":[17,29,48,227,232],"\uc788\uc2b5\ub2c8\ub2e4":[17,23,27,45,48,56,227,231,232],"\uc788\uc5b4":[228,230],"\uc788\uc5b4\uc11c":228,"\uc788\uc5b4\uc11c\ub3c4":231,"\uc788\uc5b4\uc57c":[48,230],"\uc788\uc5c8\uace0":228,"\uc788\uc5c8\ub294\uc9c0":228,"\uc788\uc5c8\ub2e4":228,"\uc788\uc73c\ub098":[45,48],"\uc788\uc73c\ub2c8":[23,231],"\uc788\uc73c\uba70":[17,45,48,228,231,232],"\uc788\uc73c\uba74":228,"\uc788\uc73c\ubbc0\ub85c":[17,230],"\uc788\uc744":[228,232],"\uc788\uc744\uae4c":228,"\uc788\uc744\uc9c0\ub294":228,"\uc788\uc74c":[17,23],"\uc788\uc74c\uc744":[29,231],"\uc788\uc9c0":[29,227,230],"\uc788\uc9c0\ub9cc":[227,228],"\uc790\uae30\ub3c4":231,"\uc790\uae30\uc735\uc790":17,"\uc790\ub3d9":[17,29,227,228,230,232],"\uc790\ub3d9\ub85c\uadf8\uc778\uc774":17,"\uc790\ub3d9\uc73c\ub85c":[17,29,45,48,230,232],"\uc790\ub3d9\uc8fc\ubb38\uacb0\uacfc":231,"\uc790\ub3d9\ucde8\uc18c\ub418\uc9c0":17,"\uc790\ub3d9\ud560\ub2f9":[230,231],"\uc790\ub3d9\ud654":228,"\uc790\ub3d9\ud654\uac00":228,"\uc790\ub8cc\ub4e4\uc744":227,"\uc790\ub8cc\ub4e4\uc774":228,"\uc790\ub8cc\ub97c":[228,231],"\uc790\ubc14\uc2a4\ud06c\ub9bd\ud2b8":228,"\uc790\ubcf8\uae08":[230,231,232],"\uc790\ubcf8\uc9c0\uc9c0":230,"\uc790\uc0b0\uc740":227,"\uc790\uc138\ud558\uac8c":228,"\uc790\uc138\ud55c":[227,230,231],"\uc790\uc2dd":29,"\uc790\uc2e0\uc5d0\uac8c":228,"\uc790\uc2e0\uc744":231,"\uc790\uc2e0\uc758":231,"\uc790\uc2e0\uc774":228,"\uc790\uc2e0\uc788\uac8c":228,"\uc790\uc5f0\uc2a4\ub7ec\uc6b4":231,"\uc790\uc5f0\uc2a4\ub7fd\uac8c":[228,231],"\uc790\uc720\ud3ec\uba67":231,"\uc790\uc8fc":230,"\uc790\uccb4\uc5c5\uc885\uc9c0\uc218":231,"\uc790\uccb4\uc801\uc73c\ub85c":231,"\uc791\ub3d9\ud558\ub294":231,"\uc791\uc131":17,"\uc791\uc131\ub418\uc5b4":231,"\uc791\uc131\ud558\uc9c0":231,"\uc791\uc131\ud55c":232,"\uc791\uc131\ud574":231,"\uc791\uc5c5\uc744":232,"\uc791\uc5c5\uc774":232,"\uc791\uc5c5\ucc98\ub9ac\ub97c":232,"\uc791\uc740":228,"\uc794\uace0":[45,231],"\uc794\uace0\uccad\uc0b0\uc0ad\uc81c":231,"\uc794\uace0\ud1b5\ubcf4":23,"\uc794\uace0\ud1b5\ubcf4\ub97c":23,"\uc794\uace0\ud3b8\uc785":231,"\uc794\uace0\ud655\uc778\uc5d0":[45,48],"\uc798":[228,231],"\uc798\uac8c":228,"\uc798\ubabb\ub418\uc5c8\ub2e4\uace0":231,"\uc7a0\uc815":231,"\uc7a1\uc544":231,"\uc7a5\uad6c\ubd84":230,"\uc7a5\ub0b4":[17,29,125,131,134],"\uc7a5\ub0b4\uc678":17,"\uc7a5\ub9c8\uac10":17,"\uc7a5\uc2dc\uc791\uc2dc\uac04":231,"\uc7a5\uc774":230,"\uc7a5\uc804":17,"\uc7a5\uc804\uc2dc\uac04\uc678":17,"\uc7a5\uc804\uc2dc\uac04\uc678\uc885\uac00":[17,45,152],"\uc7a5\uc810\uc744":228,"\uc7a5\uc810\uc774":228,"\uc7a5\uc810\uc774\ub77c\uace0":228,"\uc7a5\uc885\ub8cc":17,"\uc7a5\ud6c4":17,"\uc7a5\ud6c4\uc2dc\uac04\uc678":17,"\uc7a5\ud6c4\uc2dc\uac04\uc678\uc885\uac00":[17,45,152],"\uc7ac":228,"\uc7ac\uc2dc\uc791\ub420":232,"\uc800\uac00":[228,230,231,232],"\uc800\uac78":228,"\uc800\uc7a5":[17,23,228,231,232],"\uc800\uc7a5\ub418\ub294":228,"\uc800\uc7a5\ub418\uc5b4":230,"\uc800\uc7a5\ub41c":[17,23,230],"\uc800\uc7a5\ub41c\ub2e4":17,"\uc800\uc7a5\ud558\uace0":228,"\uc800\uc7a5\ud558\ub294\uac74":230,"\uc800\uc7a5\ud558\uba74":228,"\uc800\uc7a5\ud55c":230,"\uc800\uc7a5\ud55c\ub2e4":228,"\uc800\uc7a5\ud560":[228,232],"\uc800\ud3c9\uac00":[230,231],"\uc800\ud3c9\uac00\uc8fc":[230,231],"\uc801\uc5b4":231,"\uc801\uc5b4\ub3c4":[228,231],"\uc801\uc5b4\ubcf4\ub824\uace0":228,"\uc801\uc6a9":[17,228],"\uc801\uc6a9\uacfc":228,"\uc801\uc6a9\ub418\uba74\uc11c":232,"\uc801\uc6a9\ub418\uc9c0":228,"\uc801\uc6a9\ub418\uc9c0\ub294":228,"\uc801\uc6a9\ub41c":228,"\uc801\uc6a9\ub420":231,"\uc801\uc6a9\uc5ec\ubd80":228,"\uc801\uc6a9\ud558\uc9c0":228,"\uc801\uc6a9\ud55c\ub4ef\ud55c":228,"\uc801\uc6a9\ud574\ubcf4\ub2e4\uac00":228,"\uc801\uc6a9\ud574\ubd24\ub2e4":228,"\uc801\uc740":228,"\uc801\uc808\ud55c":[231,232],"\uc801\uc808\ud55c\uc9c0\uc5d0":228,"\uc801\uc808\ud788":231,"\uc801\ud569\ud55c":228,"\uc801\ud600\uc788\ub294":231,"\uc804":45,"\uc804\uae4c\uc9c0":230,"\uc804\ub2ec":231,"\uc804\ub2ec\ub428":17,"\uc804\ub2ec\ub429\ub2c8\ub2e4":23,"\uc804\ub2ec\ubbc0\ub85c":17,"\uc804\ub2ec\ubc1b\uace0\uc790":48,"\uc804\ub2ec\ubc1b\ub294":[230,231],"\uc804\ub2ec\ubc1b\uc2b5\ub2c8\ub2e4":48,"\uc804\ub2ec\ubc1b\uc544":[45,48],"\uc804\ub2ec\ud558\ub294":[27,48,56],"\uc804\ub2ec\ud558\ub294\ub370":17,"\uc804\ub2ec\ud558\ub3c4\ub85d":231,"\uc804\ub2ec\ud558\uba74":231,"\uc804\ub2ec\ud55c":48,"\uc804\ub2ec\ud569\ub2c8\ub2e4":[17,29,45,48],"\uc804\ub2ec\ud574":231,"\uc804\ubb38":[22,45],"\uc804\ubb38\uac00\uc774\ub2e4":228,"\uc804\ubb38\uc791\uc131":22,"\uc804\ubd80":17,"\uc804\ubd80\ub97c":17,"\uc804\uc0b0\uad00\ub828":228,"\uc804\uc1a1":17,"\uc804\uc1a1\ud558\ub294":17,"\uc804\uc1a1\ud55c":48,"\uc804\uc1a1\ud55c\ub2e4":17,"\uc804\uc1a1\ud569\ub2c8\ub2e4":17,"\uc804\uc2e0\uc778":228,"\uc804\uc5d0":17,"\uc804\uc6a9":17,"\uc804\uc6a9\uc73c\ub85c":17,"\uc804\uc6a9\ud568\uc218\uc785\ub2c8\ub2e4":17,"\uc804\uc77c":[17,228],"\uc804\uc77c\uac00":17,"\uc804\uc77c\uac00\ub97c":17,"\uc804\uc77c\uac70\ub798\ub7c9\ub300\ube44":230,"\uc804\uc77c\uac70\ub798\ub7c9\ub300\ube44\uc728":[230,231],"\uc804\uc77c\ub300\ube44":[230,231,232],"\uc804\uc77c\ub300\ube44\uae30\ud638":[230,231],"\uc804\uc77c\uc758":228,"\uc804\uc77c\uc885\uac00":[228,230,231],"\uc804\uc885\ubaa9":29,"\uc804\uc885\ubaa9\ub300\uc0c1":17,"\uc804\uccb4":[17,45,227,228,232],"\uc804\uccb4\ub97c":228,"\uc804\uccb4\uc2dc\uc7a5":17,"\uc804\uccb4\uc5d0":228,"\uc804\uccb4\uc801\uc778":[231,232],"\uc804\uccb4\uc885\ubaa9\uad6c\ubd84":45,"\uc804\uccb4\ud56d\ubaa9":228,"\uc804\ud600":231,"\uc804\ud658":17,"\uc804\ud658\ube44\uc728":230,"\uc804\ud6c4\ud574\uc11c":228,"\uc808\ub300":231,"\uc810":[231,232],"\uc810\ub4e4\uc744":[231,232],"\uc810\ub4e4\uc774":[228,231],"\uc810\uc774":231,"\uc810\uc785\ub2c8\ub2e4":[48,232],"\uc811\uadfc":231,"\uc811\uadfc\uc131":228,"\uc811\uadfc\ud558\uace0":228,"\uc811\uadfc\ud560":231,"\uc811\ubaa9\uc2dc\ud0a4\uace0\uc790":227,"\uc811\ubaa9\uc2dc\ud0a4\uae30\uc5d0\ub294":231,"\uc811\uc18d":[17,23,29,86,228,230,232],"\uc811\uc18d\ub418\uc5b4":230,"\uc811\uc18d\ub418\uc5c8\ub294\uc9c0":29,"\uc811\uc18d\ub41c":29,"\uc811\uc18d\ub9cc":17,"\uc811\uc18d\uc0c1\ud0dc":17,"\uc811\uc18d\uc0c1\ud0dc\ub97c":[17,230],"\uc811\uc18d\uc11c\ubc84":17,"\uc811\uc18d\uc2dc":232,"\uc811\uc18d\uc815\ubcf4":86,"\uc811\uc18d\uc911\uc778":232,"\uc811\uc18d\ud558\ub824\uba74":232,"\uc811\uc218":[45,48,230,231],"\uc811\ud558\uae30":231,"\uc811\ud560":228,"\uc815\uaddc\uc7a5":17,"\uc815\ub3c4":231,"\uc815\ub3c4\uac00":228,"\uc815\ub3c4\uae4c\uc9c0":228,"\uc815\ub3c4\uae4c\uc9c0\ub294":228,"\uc815\ub3c4\ub85c":228,"\uc815\ub3c4\ub85c\ub9cc":228,"\uc815\ub3c4\ub97c":228,"\uc815\ub3c4\uc5d0":228,"\uc815\ub82c\uc21c\uc11c":17,"\uc815\ub9ac\ub41c":231,"\uc815\ub9ac\ub9e4\ub9e4":[17,29],"\uc815\ub9ac\ud558\uc790\uba74":228,"\uc815\ub9d0":228,"\uc815\ubcf4":[17,227],"\uc815\ubcf4\uac00":45,"\uc815\ubcf4\uad50\ud658":23,"\uc815\ubcf4\ub098":231,"\uc815\ubcf4\ub294":228,"\uc815\ubcf4\ub370\uc774\ud130":228,"\uc815\ubcf4\ub3c4":45,"\uc815\ubcf4\ub4e4\uc740":[228,230,231],"\uc815\ubcf4\ub97c":[17,29,45,228,230,231,232],"\uc815\ubcf4\ub9cc":228,"\uc815\ubcf4\uc81c\uacf5":17,"\uc815\uc0c1":[17,29,230],"\uc815\uc0c1\ub3d9\uc791\uc744":230,"\uc815\uc0c1\uc774":29,"\uc815\uc0c1\uc774\uace0":29,"\uc815\uc0c1\uc801\uc73c\ub85c":[227,230,232],"\uc815\uc0c1\uc801\uc778":227,"\uc815\uc0c1\uc8fc\ubb38\uc73c\ub85c":[45,48],"\uc815\uc0c1\ucc98\ub9ac":[17,22,86],"\uc815\uc218":29,"\uc815\uc758":230,"\uc815\uc815":[17,45,230,231],"\uc815\uc815\ub4f1\uc744":230,"\uc815\uc815\ud560":23,"\uc815\ud558\uace0":232,"\uc815\ud655\ub3c4\uc640":228,"\uc815\ud655\ud55c":228,"\uc81c\uac70":231,"\uc81c\uac70\ud558\uace0":29,"\uc81c\uac70\ud55c\ub2e4":17,"\uc81c\uac70\ud574\uc8fc\uc5b4\uc57c":227,"\uc81c\uacf5":228,"\uc81c\uacf5\ub418\ub294":[45,227,228,231],"\uc81c\uacf5\ub418\uc9c0":[228,230],"\uc81c\uacf5\ub41c":232,"\uc81c\uacf5\ub41c\ub2e4":230,"\uc81c\uacf5\ub429\ub2c8\ub2e4":232,"\uc81c\uacf5\uc790\uac00":228,"\uc81c\uacf5\uc911\uc778":228,"\uc81c\uacf5\ud558\uace0":[228,230,231,232],"\uc81c\uacf5\ud558\ub294":[17,227,228,230,231,232],"\uc81c\uacf5\ud558\ub3c4\ub85d":231,"\uc81c\uacf5\ud558\uc9c0":228,"\uc81c\uacf5\ud55c\ub2e4":[228,230],"\uc81c\uacf5\ud569\ub2c8\ub2e4":[29,45,231,232],"\uc81c\uacf5\ud574":231,"\uc81c\ub180\ub8e8\uc158":230,"\uc81c\ub300\ub85c":[227,232],"\uc81c\ub3c4\uac1c\uc120\uc73c\ub85c":17,"\uc81c\uc0bc\uc790\uc758":228,"\uc81c\uc57d":231,"\uc81c\uc57d\uc744":231,"\uc81c\uc57d\uc774":[17,231],"\uc81c\uc678\ub294":45,"\uc81c\uc678\ud55c":[228,230,231],"\uc81c\uc791":227,"\uc81c\uc791\ud560":227,"\uc81c\ud55c":[5,29,30,86,231],"\uc81c\ud55c\ub429\ub2c8\ub2e4":30,"\uc81c\ud55c\uc5d0":[5,30],"\uc81c\ud55c\uc5ec\ubd80":231,"\uc81c\ud55c\uc744":[228,230],"\uc81c\ud55c\uc774":228,"\uc81c\ud55c\uc774\ubbc0\ub85c":230,"\uc81c\ud55c\ud558\uae30":228,"\uc81c\ud55c\ud558\ub294":228,"\uc81c\ud55c\ud574":228,"\uc870\uac74":[17,29,230],"\uc870\uac74\uac80\uc0c9":[17,22,23,29,30,45,48],"\uc870\uac74\uac80\uc0c9\uacb0\uacfc\uc5d0":17,"\uc870\uac74\uac80\uc0c9\ub3c4":17,"\uc870\uac74\uac80\uc0c9\ub9cc":17,"\uc870\uac74\uac80\uc0c9\uc2dd":29,"\uc870\uac74\uac80\uc0c9\uc5d0\ub9cc":17,"\uc870\uac74\uac80\uc0c9\uc5d0\uc11c\ub294":17,"\uc870\uac74\uac80\uc0c9\uc73c\ub85c":45,"\uc870\uac74\uac80\uc0c9\uc740":[17,30],"\uc870\uac74\uac80\uc0c9\uc744":[17,45,230],"\uc870\uac74\uac80\uc0c9\uc758":230,"\uc870\uac74\ub4e4\uacfc":230,"\uc870\uac74\ub4e4\uc744":230,"\uc870\uac74\ub4e4\uc758":230,"\uc870\uac74\ub4e4\uc774":230,"\uc870\uac74\uba85":17,"\uc870\uac74\uba85\uc73c\ub85c":17,"\uc870\uac74\uba85\uc758":17,"\uc870\uac74\uba85\uc774":17,"\uc870\uac74\ubc88\ud638":22,"\uc870\uac74\ubc88\ud638\uc640":22,"\uc870\uac74\ubd80\uc9c0\uc815\uac00":[17,45,152],"\uc870\uac74\uc2dd":[17,22,23,29,45,48],"\uc870\uac74\uc2dd\ub4e4\uc740":230,"\uc870\uac74\uc2dd\uc5d0":[17,30],"\uc870\uac74\uc2dd\uc73c\ub85c":45,"\uc870\uac74\uc2dd\uc740":[17,230],"\uc870\uac74\uc2dd\uc744":[17,29,45,230],"\uc870\uac74\uc2dd\uc758":17,"\uc870\uac74\uc2dd\uc774":[17,29,45,230],"\uc870\uac74\uc5d0":[228,230,231],"\uc870\uac74\uc744":[17,230],"\uc870\uac74\uc774":231,"\uc870\uae08\uc529":[228,231],"\uc870\uae08\uc740":228,"\uc870\uc2ec\uc2a4\ub808":228,"\uc870\uc5b8\uc740":231,"\uc870\uc778":228,"\uc870\uc808\ud558\uace0":228,"\uc870\uc815\ud55c\ub2e4":228,"\uc870\uc815\ud574\uc8fc\ub294":228,"\uc870\uc815\ud574\uc900\ub2e4":228,"\uc870\ud68c":[5,17,22,29,231],"\uc870\ud68c\uac00":23,"\uc870\ud68c\uacfc\ubd80\ud654":86,"\uc870\ud68c\uad6c\ubd84":[17,45],"\uc870\ud68c\uad6c\ubd84\uc744":17,"\uc870\ud68c\ub370\uc774\ud130\ub97c":23,"\uc870\ud68c\ub97c":30,"\uc870\ud68c\uc694\uccad":[22,23],"\uc870\ud68c\uc694\uccad\uc2dc":17,"\uc870\ud68c\uc751\ub2f5\uc73c\ub85c":23,"\uc870\ud68c\uc785\ub825\uac12":86,"\uc870\ud68c\ud558\uae30":17,"\uc870\ud68c\ud558\ub824\ub294":17,"\uc870\ud68c\ud560":[17,45],"\uc870\ud68c\ud560\ub54c":17,"\uc870\ud68c\ud568\uc218":17,"\uc870\ud68c\ud574\uc11c":17,"\uc870\ud68c\ud574\uc57c\ud55c\ub2e4":17,"\uc870\ud68c\ud69f\uc218":30,"\uc870\ud68c\ud69f\uc218\ub97c":17,"\uc874\uc7ac\ud558\uace0":17,"\uc874\uc7ac\ud558\ub294":[17,29,45,48,231],"\uc874\uc7ac\ud558\ub294\uc9c0\uc758":29,"\uc874\uc7ac\ud558\uba70":231,"\uc874\uc7ac\ud558\uc9c0":[45,48,86],"\uc880":[45,227,228,232],"\uc885\uac00":[17,228,230],"\uc885\uac00\uac00":228,"\uc885\uac00\ub294":228,"\uc885\uac00\ub300\ube44":17,"\uc885\uac00\ub85c":17,"\uc885\uac00\ub97c":228,"\uc885\uac00\uc640":228,"\uc885\uac00\ud574\uc11c":228,"\uc885\uadfc\ub2f9":230,"\uc885\ub8cc":[45,48,232],"\uc885\ub8cc\ub418\uba74":17,"\uc885\ub8cc\ub418\uc5c8\uae30":232,"\uc885\ub8cc\ub429\ub2c8\ub2e4":48,"\uc885\ub8cc\uc2dc\uc5d0\ub3c4":17,"\uc885\ub8cc\uc2dc\ud0a4\uac70\ub098":232,"\uc885\ub8cc\uc5c6\uc774":17,"\uc885\ub8cc\ud558\uace0":232,"\uc885\ub8cc\ud558\ub3c4\ub85d":230,"\uc885\ub8cc\ud560":17,"\uc885\ub958\ub97c":29,"\uc885\ubaa9":[17,29,45],"\uc885\ubaa9\uac04":17,"\uc885\ubaa9\uac1c\uc218":17,"\uc885\ubaa9\uacfc":17,"\uc885\ubaa9\ub2e8\uc704\ub85c":23,"\uc885\ubaa9\ub3c4":17,"\uc885\ubaa9\ub4e4\uacfc":17,"\uc885\ubaa9\ub4e4\uc5d0":[45,230],"\uc885\ubaa9\ub4e4\uc5d0\uc11c\ub294":228,"\uc885\ubaa9\ub4e4\uc740":17,"\uc885\ubaa9\ub4e4\uc744":17,"\uc885\ubaa9\ub4e4\uc758":[45,230],"\uc885\ubaa9\ub9ac\uc2a4\ud2b8":[17,23],"\uc885\ubaa9\ub9ac\uc2a4\ud2b8\ub97c":23,"\uc885\ubaa9\ub9c8\ub2e4":45,"\uc885\ubaa9\ub9c8\uc2a4\ud130\uac31\uc2e0":231,"\uc885\ubaa9\ub9cc":17,"\uc885\ubaa9\uba85":[17,230,231,232],"\uc885\ubaa9\uba85\uc744":17,"\uc885\ubaa9\ubcc4":[17,231],"\uc885\ubaa9\ubcc4\ud22c\uc790\uc790\uae30\uad00\ubcc4\uc694\uccad":231,"\uc885\ubaa9\ubcc4\ud504\ub85c\uadf8\ub7a8\ub9e4\ub9e4":231,"\uc885\ubaa9\ubcc4\ud504\ub85c\uadf8\ub7a8\ub9e4\ub9e42":231,"\uc885\ubaa9\ubd84\ub958":29,"\uc885\ubaa9\ubd84\ub958\ub4f1":17,"\uc885\ubaa9\uc0c1\ud0dc":17,"\uc885\ubaa9\uc0c1\ud0dc\ub97c":17,"\uc885\ubaa9\uc218":22,"\uc885\ubaa9\uc2dc\uc138":228,"\uc885\ubaa9\uc5d0":[17,228],"\uc885\ubaa9\uc5d0\ub300\ud55c":23,"\uc885\ubaa9\uc73c\ub85c":228,"\uc885\ubaa9\uc740":17,"\uc885\ubaa9\uc744":[17,23,29],"\uc885\ubaa9\uc758":[17,29,45,228,232],"\uc885\ubaa9\uc774":[17,23,228,230],"\uc885\ubaa9\uc778":[17,29],"\uc885\ubaa9\uc778\uc9c0":23,"\uc885\ubaa9\uc815\ubcf4":[228,230,231],"\uc885\ubaa9\uc870\ud68ctr\uc744":17,"\uc885\ubaa9\ucf54\ub4dc":[17,23,45,228,230,231,232],"\uc885\ubaa9\ucf54\ub4dc1":17,"\uc885\ubaa9\ucf54\ub4dc2":17,"\uc885\ubaa9\ucf54\ub4dc\uac00":23,"\uc885\ubaa9\ucf54\ub4dc\uac04":17,"\uc885\ubaa9\ucf54\ub4dc\ub97c":[17,45,228],"\uc885\ubaa9\ucf54\ub4dc\ub9cc":17,"\uc885\ubaa9\ucf54\ub4dc\uc5c6\uc74c":22,"\uc885\ubaa9\ucf54\ub4dc\uc5d0":[17,29],"\uc885\ubaa9\ucf54\ub4dc\uc640":17,"\uc885\ubaa9\ucf54\ub4dc\uc758":17,"\uc885\ubaa9\ucf54\ub4dcn":17,"\uc885\ubaa9\ud22c\uc790\uc790":231,"\uc885\ubaa9\ud3ec\ucc29\uc774\ud0c8":231,"\uc885\uc885":[228,232],"\uc88b\uaca0\ub2e4":228,"\uc88b\uaca0\ub2e4\uace0":231,"\uc88b\uc2b5\ub2c8\ub2e4":232,"\uc88b\uc740":228,"\uc88b\uc9c0\ub9cc":228,"\uc8c4\ub2e4":231,"\uc8fc":45,"\uc8fc\uac00":[228,230],"\uc8fc\uac00\ub294":228,"\uc8fc\uac00\ub97c":228,"\uc8fc\uac00\uc218\uc815\ube44\uc728":228,"\uc8fc\uac00\uc218\uc815\ube44\uc728\uc5d0":228,"\uc8fc\uace0":228,"\uc8fc\uae30\uc801\uc73c\ub85c":[228,232],"\uc8fc\ub294":230,"\uc8fc\ub2e8\uc704":228,"\uc8fc\ub85c":[29,228,230,231],"\uc8fc\ubb38":[17,45,48,230],"\uc8fc\ubb38\uac00\uaca9":[17,230,231],"\uc8fc\ubb38\uac00\uaca9\uc740":17,"\uc8fc\ubb38\uac00\uaca9\uc774":22,"\uc8fc\ubb38\uac00\ub2a5\uc218\ub7c9":230,"\uc8fc\ubb38\uac00\ub2a5\ud558\uba70":17,"\uc8fc\ubb38\uac70\ubd80":[45,48],"\uc8fc\ubb38\uac70\ubd80\ub4f1\uc758":[45,48],"\uc8fc\ubb38\uac74\uc218\uac00":[45,48],"\uc8fc\ubb38\uacb0\uacfc":231,"\uc8fc\ubb38\uacfc":[17,45,48,152],"\uc8fc\ubb38\uacfc\ubd80\ud654":86,"\uc8fc\ubb38\uad00\ub828":[5,48],"\uc8fc\ubb38\uad6c\ubd84":230,"\uc8fc\ubb38\uae4c\uc9c0":230,"\uc8fc\ubb38\ub2e8\uac00":[17,45],"\uc8fc\ubb38\ub9cc":[17,45,152],"\uc8fc\ubb38\ubc1b\uc740":[45,48],"\uc8fc\ubb38\ubc88\ud638":[45,230],"\uc8fc\ubb38\ubc88\ud638\uac00":[45,48],"\uc8fc\ubb38\uc0c1\ud0dc":[230,231],"\uc8fc\ubb38\uc218\ub7c9":[17,22,45,86,230,231],"\uc8fc\ubb38\uc218\ub7c9\uc774":[22,230],"\uc8fc\ubb38\uc21c":45,"\uc8fc\ubb38\uc2dc":17,"\uc8fc\ubb38\uc694\uccad\ud558\uba74":17,"\uc8fc\ubb38\uc720\ud615":[17,45,152,230,231],"\uc8fc\ubb38\uc740":17,"\uc8fc\ubb38\uc744":[17,48,230],"\uc8fc\ubb38\uc758":[45,48],"\uc8fc\ubb38\uc774":23,"\uc8fc\ubb38\uc774\ub098":[27,56],"\uc8fc\ubb38\uc77c\ub54c":17,"\uc8fc\ubb38\uc77c\uc790":45,"\uc8fc\ubb38\uc785\ub825\uac11":86,"\uc8fc\ubb38\uc804\uc1a1":[22,23],"\uc8fc\ubb38\uc811\uc218":23,"\uc8fc\ubb38\uc870\uac74\uc218\uc815":231,"\uc8fc\ubb38\uc885\ub958":17,"\uc8fc\ubb38\ucc98\ub9ac\uae4c\uc9c0":231,"\uc8fc\ubb38\ucc98\ub9ac\ub294":230,"\uc8fc\ubb38\uccb4\uacb0":231,"\uc8fc\ubb38\uccb4\uacb0\uc11c\ubc84\uc0c1\ud0dc":231,"\uc8fc\ubb38\uccb4\uacb0\ud1b5\ubcf4":23,"\uc8fc\ubb38\ucde8\uc18c\ub098":230,"\uc8fc\ubb38\ud568\uc218\uc785\ub2c8\ub2e4":17,"\uc8fc\uc18c\ub97c":[228,231],"\uc8fc\uc2dd":[17,29,45,228,231],"\uc8fc\uc2dd\uac70\ub798\uc6d0":231,"\uc8fc\uc2dd\uae30\ubcf8\uc815\ubcf4":[231,232],"\uc8fc\uc2dd\uae30\ubcf8\uc815\ubcf4\uc694\uccad":[230,231,232],"\uc8fc\uc2dd\ub2f9\uc77c\uac70\ub798\uc6d0":231,"\uc8fc\uc2dd\uc0c1\ud558\ud55c":231,"\uc8fc\uc2dd\uc120\ubb3c":17,"\uc8fc\uc2dd\uc120\ubb3c\ud638\uac00\uc794\ub7c9":231,"\uc8fc\uc2dd\uc120\uc635":17,"\uc8fc\uc2dd\uc218":230,"\uc8fc\uc2dd\uc218\ub97c":29,"\uc8fc\uc2dd\uc2dc\uac04\uc678\ud638\uac00":231,"\uc8fc\uc2dd\uc2dc\uc138":230,"\uc8fc\uc2dd\uc608\uc0c1\uccb4\uacb0":231,"\uc8fc\uc2dd\uc635\uc158":17,"\uc8fc\uc2dd\uc635\uc158\uc2dc\uc138":231,"\uc8fc\uc2dd\uc635\uc158\uc774\ub860\uac00":231,"\uc8fc\uc2dd\uc635\uc158\ud638\uac00\uc794\ub7c9":231,"\uc8fc\uc2dd\uc6b0\uc120\ud638\uac00":[230,231],"\uc8fc\uc2dd\uc744":228,"\uc8fc\uc2dd\uc758":[29,45],"\uc8fc\uc2dd\uc77c\ubd09\ucc28\ud2b8":231,"\uc8fc\uc2dd\uc77c\ubd09\ucc28\ud2b8\uc870\ud68c":231,"\uc8fc\uc2dd\uc77c\ubd09\ucc28\ud2b8\uc870\ud68c\uc694\uccad":231,"\uc8fc\uc2dd\uc885\ubaa9":17,"\uc8fc\uc2dd\uc885\ubaa9\uc815\ubcf4":231,"\uc8fc\uc2dd\uc8fc\ubb38":17,"\uc8fc\uc2dd\ucc44\uad8c\uad6c\ubd84":45,"\uc8fc\uc2dd\uccb4\uacb0":[230,231],"\uc8fc\uc2dd\ud22c\uc790\ub97c":228,"\uc8fc\uc2dd\ud638\uac00\uc794\ub7c9":231,"\uc8fc\uc5b4\uc57c":231,"\uc8fc\uc5b4\uc9c4":[17,29,45,230,231],"\uc8fc\uc694":232,"\uc8fc\uc694\ud55c":230,"\uc8fc\uc758":45,"\uc8fc\uc758\uac00":48,"\uc8fc\uc758\ud558\uc154\uc57c":17,"\uc8fc\uc81c":228,"\uc8fc\uccb4\uac00":228,"\uc8fc\uccb4\ub9c8\ub2e4":228,"\uc904":48,"\uc904\uc529":227,"\uc904\uc77c":232,"\uc911":[17,45,227,228,231,232],"\uc911\uac04\ub2e8\uacc4\uc758":232,"\uc911\uac04\uc998\uc5d0":228,"\uc911\uad6d":231,"\uc911\ubcf5":17,"\uc911\ubcf5\ub418\ub294":228,"\uc911\ubd84\ub958":17,"\uc911\uc18c\ud615":[230,231],"\uc911\uc5d0":[228,231,232],"\uc911\uc694\ud558\ub2e4":228,"\uc911\uc694\ud558\uc9c0":228,"\uc911\uc774\ub2e4":228,"\uc911\uc810\uc801\uc73c\ub85c":231,"\uc911\uc9c0":17,"\uc911\uc9c0\ud558\uac70\ub098":17,"\uc911\uc9c0\ud560":17,"\uc911\uc9c0\ud574\uc57c\ud55c\ub2e4":17,"\uc911\uc9c0\ud574\uc918\uc57c":17,"\uc911\uc9c0tr\uc744":17,"\uc911\ud615\uc8fc":17,"\uc989":17,"\uc989\uc2dc":[29,48],"\uc99d\uac70\uae08":[17,23,29,231],"\uc99d\uac70\uae08n":17,"\uc99d\uad8c\uc0ac":228,"\uc99d\uad8c\uc0ac\ub294":228,"\uc99d\uad8c\uc0ac\ub4e4":228,"\uc99d\uad8c\uc0ac\ub97c":228,"\uc99d\uad8c\uc0ac\ub9c8\ub2e4":228,"\uc99d\uad8c\uc0ac\uc5d0":228,"\uc99d\uad8c\uc0ac\uc5d0\uc11c":228,"\uc9c0\uae08":228,"\uc9c0\ub9cc":228,"\uc9c0\uc218\uc120\ubb3c":17,"\uc9c0\uc218\uc120\ubb3c\ucf54\ub4dc":17,"\uc9c0\uc218\uc120\uc635":17,"\uc9c0\uc218\uc2a4\ud504\ub808\ub4dc":17,"\uc9c0\uc218\uc635\uc158":17,"\uc9c0\uc2dd\ub4e4\uc744":231,"\uc9c0\uc2dd\ub9cc":231,"\uc9c0\uc6d0":[17,231],"\uc9c0\uc6d0\ub418\ub294":227,"\uc9c0\uc6d0\uc548\ud568":17,"\uc9c0\uc6d0\ud558\uace0":231,"\uc9c0\uc6d0\ud558\uae30":227,"\uc9c0\uc6d0\ud558\ub294":[29,228,231],"\uc9c0\uc6d0\ud558\uc9c0":[17,23,45,231],"\uc9c0\uc6d0\ud558\uc9c4":17,"\uc9c0\uc6d0\ud569\ub2c8\ub2e4":[45,48],"\uc9c0\uc815":[17,230,231],"\uc9c0\uc815\uac00":[17,45,152],"\uc9c0\uc815\uac00fok":[17,45,152],"\uc9c0\uc815\uac00ioc":[17,45,152],"\uc9c0\uc815\ub41c":29,"\uc9c0\uc815\ud558\ub294":17,"\uc9c0\uc815\ud55c":17,"\uc9c0\uc815\ud560":17,"\uc9c0\uc9c0":231,"\uc9c0\ud45c":231,"\uc9c1\uad00\uc801\uc785\ub2c8\ub2e4":232,"\uc9c1\uc811":[45,48,228,230,231,232],"\uc9c1\uc811\uc801\uc73c\ub85c":[228,230,231,232],"\uc9c1\uc811\uc801\uc778":231,"\uc9c4\ud589":232,"\uc9c4\ud589\ub418\uba74\uc11c":231,"\uc9c4\ud589\ub418\uc5b4":227,"\uc9c4\ud589\ub429\ub2c8\ub2e4":232,"\uc9c4\ud589\ud558\uace0":[29,227],"\uc9c4\ud589\ud558\uba74\uc11c":228,"\uc9c4\ud589\ud558\uc9c0\ub294":230,"\uc9c4\ud589\ud55c":29,"\uc9c4\ud589\ud55c\ub2e4":[228,230],"\uc9c4\ud589\ud560":228,"\uc9c4\ud589\ud569\ub2c8\ub2e4":[29,227,232],"\uc9c4\ud589\ud574\ub450\ub294":228,"\uc9d1\uc5d0\uc11c":228,"\uc9da\uc5b4\ubcf4\uba74":232,"\uc9dc\ub294":232,"\uc9e7\uace0":231,"\ucabd\ub3c4":231,"\ucb49":228,"\ucc28\ub2e8\ub2f9\ud560":228,"\ucc28\ub840\uc785\ub2c8\ub2e4":227,"\ucc28\uc120\ucc45\uc73c\ub85c":228,"\ucc28\uc774\uac00":[23,228],"\ucc28\uc774\ub294":[231,232],"\ucc28\uc774\ub85c":228,"\ucc28\uc774\ub97c":228,"\ucc28\uc774\ubcf4\ub2e4":228,"\ucc28\uc774\uc774\uc9c0":228,"\ucc28\uc774\uc810\uc740":48,"\ucc28\uc774\uc810\uc774\ub77c\uba74":232,"\ucc28\ud2b8":[17,45,228],"\ucc28\ud2b8\ub370\uc774\ud130\ub97c":17,"\ucc28\ud2b8\uc870\ud68c":17,"\ucc28\ud2b8\uc870\ud68c\ub294":17,"\ucc28\ud2b8\ud654\uba74":228,"\ucc38\uace0":[231,232],"\ucc38\uace0\ub85c":[228,230,232],"\ucc38\uace0\ub9cc":227,"\ucc38\uace0\uc790\ub8cc\ub97c":231,"\ucc38\uace0\ud558\uace0":231,"\ucc38\uace0\ud558\uae30":230,"\ucc38\uace0\ud558\uba74\uc11c":228,"\ucc38\uace0\ud558\uc138\uc694":[227,231,232],"\ucc38\uace0\ud558\uc2dc\ub294":232,"\ucc38\uace0\ud558\uc2dc\uba74":[17,232],"\ucc38\uace0\ud558\uc2e4":231,"\ucc38\uace0\ud558\uc790":230,"\ucc38\uace0\ud560":228,"\ucc38\uace0\ud560\ub9cc\ud55c":232,"\ucc38\uace0\ud574":231,"\ucc38\uc744":29,"\ucc38\uc870":[4,232],"\ucc3d":[17,228],"\ucc3d\uc5d0":228,"\ucc3d\uc5d0\uc11c":[228,232],"\ucc3d\uc744":232,"\ucc3d\uc774":[17,232],"\ucc3e\ub294\uac8c":228,"\ucc3e\ub2e4\ubcf4\ub2c8":228,"\ucc3e\ub2e4\ubcf4\uba74":228,"\ucc3e\uc544\uc11c":227,"\ucc3e\uc744":227,"\ucc44\uad8c":45,"\ucc44\uad8c\uccb4\uacb0":231,"\ucc44\uad8c\ud638\uac00\uc794\ub7c9":231,"\ucc44\ub110k\uc2e4\uc2dc\uac04\ud2f0\ucee4":231,"\ucc44\uc6b8":228,"\ucc44\uc6cc\ub123\uc2b5\ub2c8\ub2e4":232,"\ucc45\uc758":232,"\ucc45\uc784\ub3c4":231,"\ucc98\ub7fc":228,"\ucc98\ub9ac":[22,23,29,230,232],"\ucc98\ub9ac\uac00":[29,230,231,232],"\ucc98\ub9ac\uae4c\uc9c0":230,"\ucc98\ub9ac\ub418\ub294":232,"\ucc98\ub9ac\ub418\uba70":230,"\ucc98\ub9ac\ub429\ub2c8\ub2e4":232,"\ucc98\ub9ac\ub97c":[29,45,48,227,228,230,232],"\ucc98\ub9ac\ubc29\ubc95\uc774":17,"\ucc98\ub9ac\ubc29\uc2dd\uc744":228,"\ucc98\ub9ac\ubc29\uc2dd\uc774\ub098":228,"\ucc98\ub9ac\ubd80\ud130":231,"\ucc98\ub9ac\uc640":[48,228,232],"\ucc98\ub9ac\ud558\uace0":[45,48,232],"\ucc98\ub9ac\ud558\uae30":[231,232],"\ucc98\ub9ac\ud558\ub294":[228,230,232],"\ucc98\ub9ac\ud558\ub358":230,"\ucc98\ub9ac\ud558\ub3c4\ub85d":48,"\ucc98\ub9ac\ud55c\ub2e4":228,"\ucc98\ub9ac\ud55c\ub2e4\ub294":48,"\ucc98\ub9ac\ud560":[17,29,48,228,232],"\ucc98\ub9ac\ud569\ub2c8\ub2e4":[29,45,231,232],"\ucc98\ub9ac\ud574":[45,48,228,231],"\ucc98\ub9ac\ud574\uc8fc\ub294":230,"\ucc98\ub9ac\ud574\uc8fc\uc5b4\uc57c":230,"\ucc98\uc74c":[228,232],"\ucc98\uc74c\ubd80\ud130":231,"\ucc98\uc74c\uc73c\ub85c":231,"\ucc98\uc74c\uc758":228,"\ucca8\ubd80\ub41c":228,"\uccab":232,"\uccab\ubc88\uc9f8":[17,29,228],"\uccab\ubc88\uc9f8\ub85c":[230,231],"\uccad\uc0b0\uc2dc\uc791":231,"\uccad\uc0b0\uc644\ub8cc":231,"\uccb4\uacb0":[17,45,48,230,231],"\uccb4\uacb0\uac00":[17,230],"\uccb4\uacb0\uac15\ub3c4":230,"\uccb4\uacb0\uad6c\ubd84":[23,45],"\uccb4\uacb0\ub0b4\uc5ed\ub9cc":45,"\uccb4\uacb0\ub204\uacc4\uae08\uc561":230,"\uccb4\uacb0\ub370\uc774\ud130\ub97c":23,"\uccb4\uacb0\ub420\ub54c\uae4c\uc9c0":[45,48],"\uccb4\uacb0\ub7c9":[230,231],"\uccb4\uacb0\ubc88\ud638":230,"\uccb4\uacb0\uc2dc\uac04":230,"\uccb4\uacb0\uc794\uace0":17,"\uccb4\uacb0\ud1b5\ubcf4":23,"\uccb4\ud06c":228,"\uccb4\ud06c\ud558\uace0":232,"\uccb4\ud06c\ud569\ub2c8\ub2e4":232,"\uccb4\ud06c\ud574\uc11c":232,"\ucd08":228,"\ucd08\uacfc":[22,86],"\ucd08\uacfc\uc624\ub958":22,"\ucd08\uacfc\ud558\ub294":17,"\ucd08\uae30\ud654":22,"\ucd08\ub85d\uc0c9":232,"\ucd08\ub85d\uc0c9\uacfc":232,"\ucd08\uc810\uc744":231,"\ucd1d":232,"\ucd1d\ub7c9\uc744":228,"\ucd1d\ub9e4\ub3c4\uac74\uc218":230,"\ucd1d\ub9e4\ub3c4\uc794\ub7c9":230,"\ucd1d\ub9e4\uc218\uac74\uc218":230,"\ucd1d\ub9e4\uc218\uc794\ub7c9":230,"\ucd1d\ub9e4\uc785\uac00":230,"\ucd1d\ubc1c\ud589\uc8fc\uc218\uc758":22,"\ucd5c\uadfc":[228,231],"\ucd5c\uadfc\ubd80\ud130":228,"\ucd5c\uadfc\uc6d4\ubb3c":17,"\ucd5c\uadfc\uc6d4\ubb3c\uac00":17,"\ucd5c\uadfc\uc6d4\uc120\ubb3c":17,"\ucd5c\uadfc\uc6d4\uc2a4\ud504\ub808\ub4dc":17,"\ucd5c\uadfc\uc758":228,"\ucd5c\ub300":[5,17,30],"\ucd5c\ub300\ub85c":228,"\ucd5c\ub300\ud55c":[228,230],"\ucd5c\uc18c":17,"\ucd5c\uc18c\ud55c\uc758":232,"\ucd5c\uc2e0":[227,228],"\ucd5c\uc2e0\uc73c\ub85c":232,"\ucd5c\uc2e0\uc758":[17,227],"\ucd5c\uc545\uc758":228,"\ucd5c\uc6b0\uc120\uc9c0\uc815\uac00":[17,45,152],"\ucd5c\uc720\ub9ac\uc9c0\uc815\uac00":[17,45,152],"\ucd5c\uc720\ub9acfok":[17,45,152],"\ucd5c\uc720\ub9acioc":[17,45,152],"\ucd5c\uc885":227,"\ucd5c\uc885\uc801\uc73c\ub85c":[45,228,231,232],"\ucd5c\uc885\uc801\uc73c\ub860":231,"\ucd5c\ucd08":[17,45,48,230,232],"\ucd5c\ucd08\ub85c":232,"\ucd94\uac00":[17,45,230],"\ucd94\uac00\uac00":[230,231],"\ucd94\uac00\ub41c":232,"\ucd94\uac00\ub85c":[45,48,227,228],"\ucd94\uac00\uc801\uc73c\ub85c":[228,231],"\ucd94\uac00\uc801\uc778":[45,48,227,230],"\ucd94\uac00\uc870\ud68c":23,"\ucd94\uac00\ud558\uac8c":17,"\ucd94\uac00\ud558\uace0":231,"\ucd94\uac00\ud558\ub294":232,"\ucd94\uac00\ud558\uc600\uc744":17,"\ucd94\uac00\ud55c\ub2e4":228,"\ucd94\uac00\ud574\ubcf4\uc790":228,"\ucd94\uac00\ud574\uc11c":17,"\ucd94\uad6c\ud558\ub294":231,"\ucd94\ub824\uc11c":231,"\ucd94\ub860":[230,231],"\ucd94\uc815\uc870\ud68c":45,"\ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4":232,"\ucd94\ucc9c\uc2dd\ub4e4\uc744":230,"\ucd94\ucc9c\ud558\ub294":[227,231],"\ucd94\uce21\ud574\ubcf8\ub2e4":228,"\ucd94\uce21\ud574\ubcfc":228,"\ucd94\ud6c4":[227,231],"\ucd94\ud6c4\uc5d0":232,"\ucd9c\ub825":[17,230,231,232],"\ucd9c\ub825\uac12\uc758":17,"\ucd9c\ub825\uacfc":230,"\ucd9c\ub825\ub418\ub294":[227,232],"\ucd9c\ub825\ub418\ub3c4\ub85d":17,"\ucd9c\ub825\uc21c\uc11c\uc5d0":17,"\ucd9c\ub825\uc774":230,"\ucd9c\ub825\ud56d\ubaa9":17,"\ucd9c\ucc98\uc5d0":228,"\ucd9c\ucc98\uc5d0\uc11c":228,"\ucd9c\ucc98\uc758":228,"\ucd9c\ucc98\uc774\uc9c0":228,"\ucda9\ub3cc\uc774":227,"\ucda9\ubd84\ud55c":231,"\ucda9\ubd84\ud788":[228,231],"\ucde8\uc18c":[17,230,231],"\ucde8\uc18c\uc2dc":[17,45],"\ucde8\uc18c\ud558\ub294":230,"\uce21\uba74\uc5d0\uc11c":228,"\uce21\uba74\uc5d0\uc11c\ub294":228,"\uce21\uc5d0\uc11c":[45,48],"\uce68\ud574":231,"\ucee4\ub125\uc158":230,"\ucee4\ub9e8\ub4dc":232,"\ucee4\ub9e8\ub4dc\ub4e4":232,"\ucee4\ub9e8\ub4dc\ub85c":231,"\ucee4\ub9e8\ub4dc\ub97c":[227,231,232],"\ucee4\ubc84\ud569\ub2c8\ub2e4":29,"\ucee4\uc9c4\ub2e4":228,"\ucee8\ud14d\uc2a4\ud2b8":[48,231],"\ucee8\ud2b8\ub864":[231,232],"\ucee8\ud2b8\ub864\uc5d0\uc11c":231,"\ucee8\ud2b8\ub864\uc774":232,"\uceec\ub7ec\ub808\uc774":230,"\uceec\ub7fc\ub4e4\ub85c":228,"\uceec\ub7fc\ub4e4\ub85c\ub9cc":228,"\uceec\ub7fc\ub4e4\ub9cc":228,"\uceec\ub7fc\ub9cc":228,"\uceec\ub7fc\uc218\uc5d0":228,"\uceec\ub7fc\uc744":228,"\ucef4\ud4e8\ud130\uc5d0":228,"\ucf00\uc774\uc2a4\ub4e4\uc744":45,"\ucf00\uc774\uc2a4\ub97c":228,"\ucf00\uc774\uc2a4\uc5d0\uc11c":[45,48],"\ucf00\uc774\uc2a4\uc640\ub294":228,"\ucf00\uc774\uc2a4\uc640\uc758":228,"\ucf54\ub125\uc2a4":17,"\ucf54\ub125\uc2a4\uacbd\ub9e4\ub9e4\uccb4\uacb0":231,"\ucf54\ub4dc":[17,23,29,230,232],"\ucf54\ub4dc\uac00":228,"\ucf54\ub4dc\uac04":17,"\ucf54\ub4dc\ub294":228,"\ucf54\ub4dc\ub85c":17,"\ucf54\ub4dc\ub97c":[17,48,228,230,231],"\ucf54\ub4dc\ub9ac\uc2a4\ud2b8\ub97c":17,"\ucf54\ub4dc\uba85":17,"\ucf54\ub4dc\ubc88\ud638\uac00":[27,56],"\ucf54\ub4dc\ubc88\ud638\ub294":[23,27,56],"\ucf54\ub4dc\ubc88\ud638\ub85c":[27,56],"\ucf54\ub4dc\ubc88\ud638\ub97c":23,"\ucf54\ub4dc\uc21c":17,"\ucf54\ub4dc\uc5d0\uc11c":[17,230],"\ucf54\ub4dc\uc5d0\uc11c\ub294":48,"\ucf54\ub4dc\uc640":17,"\ucf54\ub4dc\uc758":[17,48],"\ucf54\ub4dc\uc911":17,"\ucf54\uba54\ub860":230,"\ucf54\uc2a4\ub2e5":[3,17,29,125,131,134,228],"\ucf54\uc2a4\ucf64\uc774\ub77c\ub294":228,"\ucf54\uc2a4\ud53c":[17,29],"\ucf54\uc2a4\ud53c200\uc9c0\uc218\uc694\uccad":231,"\ucf54\uc2a4\ud53c\uc9c0\uc218200":17,"\ucf54\uc6e8\uc774":230,"\ucf54\uc6f0\ud328\uc158":230,"\ucf58\uc194\uc5d0\uc11c":232,"\ucf5c":17,"\ucf5c\ub9c8\ube44\uc564\uc5d0\uc774\uce58":230,"\ucf5c\ubc31":[29,231,232],"\ucf5c\ubc31\ud568\uc218":232,"\ucf5c\uc635\uc158":17,"\ucf5c\ud48b\uc73c\ub85c":17,"\ucfe0\ucfe0\ud640\ub529\uc2a4":230,"\ucfe0\ucfe0\ud648\uc2dc\uc2a4":[230,231],"\ud000\ud2b8\ud22c\uc790\ub97c":232,"\ud06c\uac8c":228,"\ud06c\uae30\uac00":17,"\ud06c\ub2e4":228,"\ud06c\ub864\ub7ec\ub97c":228,"\ud06c\ub864\ub9c1\uc744":228,"\ud06c\ub9ac\uc2a4\uc5d0\ud504\uc564\uc528":230,"\ud06c\ub9ac\uc2a4\ud0c8\uc2e0\uc18c\uc7ac":230,"\ud070":[17,231,232],"\ud074\ub77c\uc774\uc5b8\ud2b8":[45,48,227,231],"\ud074\ub77c\uc774\uc5b8\ud2b8\ub294":48,"\ud074\ub77c\uc774\uc5b8\ud2b8\ub97c":231,"\ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0":[45,48],"\ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\ub3c4":[45,48],"\ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c":45,"\ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c\ub294":231,"\ud074\ub798\uc2a4":[45,48],"\ud074\ub798\uc2a4\ub4e4\uc5d0":232,"\ud074\ub798\uc2a4\ub4e4\uc744":232,"\ud074\ub798\uc2a4\ub4e4\uc774":232,"\ud074\ub798\uc2a4\ub97c":48,"\ud074\ub860\ud558\uac70\ub098":227,"\ud074\ub9ad":[228,231],"\ud074\ub9ad\ud574":228,"\ud0a4\uac12\uc73c\ub85c":227,"\ud0a4\ubcf4\ub4dc":[17,29,232],"\ud0a4\uc6c0":[227,232],"\ud0a4\uc6c0\uc5d0\uc11c":[17,230,231],"\ud0a4\uc6c0\uc885\ud569\ucc28\ud2b8":228,"\ud0a4\uc6c0\uc99d\uad8c":[29,45,48,228,232],"\ud0a4\uc6c0\uc99d\uad8c\uacfc":228,"\ud0a4\uc6c0\uc99d\uad8c\ub9cc":228,"\ud0a4\uc6c0\uc99d\uad8c\uc5d0\uc11c":230,"\ud0a4\uc6c0\uc99d\uad8c\uc758":[227,228],"\ud0a4\uc6c0\uc99d\uad8c\uc774":228,"\ud0c0\uc774\ubc0d\uc5d0":232,"\ud0c0\uc778":86,"\ud0c0\uc778\uacc4\uc88c\uc0ac\uc6a9":22,"\ud0c0\uc784\ud504\ub808\uc784\uc73c\ub85c":228,"\ud0c0\uc784\ud504\ub808\uc784\uc758":228,"\ud0c0\uc784\ud504\ub808\uc784\ud558\uc5d0":228,"\ud0c0\uc785":[23,230,232],"\ud0c0\uc785\ub9cc":[45,48],"\ud0c0\uc785\ubcc4":231,"\ud0c0\uc785\uc73c\ub85c":231,"\ud0c0\uc785\uc740":230,"\ud0c0\uc785\uc758":[17,230],"\ud0d1\uc7ac":[227,232],"\ud0d1\uc7ac\ud55c":228,"\ud0dc\uadf8":17,"\ud0dc\uadf8\uac12":17,"\ud0dc\uadf8\uac12\uc5d0":17,"\ud0dc\uc591\uad11_\ud3f4\ub9ac\uc2e4\ub9ac\ucf58":17,"\ud0ec\ud50c\ub9bf\uc744":231,"\ud0ed":228,"\ud0ed\uc5d0\uc11c":17,"\ud130\ubbf8\ub110\uc5d0\uc11c":[227,232],"\ud130\ubbf8\ub110\uc744":232,"\ud14c\ub9c8\uba85\uc744":17,"\ud14c\ub9c8\uc21c":17,"\ud14c\ub9c8\ucf54\ub4dc":17,"\ud14c\ub9c8\ucf54\ub4dc\uc5d0":17,"\ud14c\ub9c8\ucf54\ub4dc\uc640":17,"\ud14c\uc2a4\ud2b8":[227,232],"\ud14c\uc2a4\ud2b8\ub418\uc9c0":231,"\ud14c\uc2a4\ud2b8\ub97c":[230,231],"\ud14c\uc2a4\ud2b8\ud574\ubcfc":230,"\ud14c\uc2a4\ud2b8\ud574\ubd05\uc2dc\ub2e4":227,"\ud14c\uc2a4\ud2b8\ud588\ub358":227,"\ud14c\uc774\ube14":228,"\ud14c\uc774\ube14\uc131":231,"\ud1b1\ub2c8\ubc84\ud2bc\uc744":228,"\ud1b5\uacc4":228,"\ud1b5\ub85c\ub85c":231,"\ud1b5\ubcf4\uc5c6\uc774":[27,56],"\ud1b5\uc2e0":[17,22],"\ud1b5\uc2e0\uacb0\uacfc":17,"\ud1b5\uc2e0\ubd88\uac00":17,"\ud1b5\uc2e0\uc744":227,"\ud1b5\uc2e0\ud558\uc5ec":232,"\ud1b5\ud55c":[29,227,231],"\ud1b5\ud574":[45,48,227,228,230,231,232],"\ud1b5\ud574\uc11c":[227,228,231,232],"\ud22c\uc790\uacbd\uace0":[17,29],"\ud22c\uc790\uc704\ud5d8":[17,29],"\ud22c\uc790\uc720\uc758":[17,29],"\ud22c\uc790\uc720\uc758\uc885\ubaa9":[17,29],"\ud22c\uc790\uc720\uc758\uc885\ubaa9\uc73c\ub85c":29,"\ud22c\uc790\uc720\uc758\uc885\ubaa9\uc778\uc9c0":17,"\ud22c\uc790\uc735\uc758\uc885\ubaa9":29,"\ud22c\uc790\uc790\ubcc4\ub9e4\ub9e4":231,"\ud22c\uc790\uc790ticker":231,"\ud22c\uc790\uc8fc\uc758":[17,29],"\ud22c\uc790\uc8fc\uc758\ud658\uae30\uc885\ubaa9":[17,29],"\ud234":228,"\ud234\uc744":228,"\ud234\uc785\ub2c8\ub2e4":231,"\ud2b8\ub798\ud53d\uc744":228,"\ud2b8\ub808\uc774":232,"\ud2b8\ub808\uc774\ub529":227,"\ud2b8\ub808\uc774\ub529\ubdf0":228,"\ud2b8\ub808\uc774\ub529\uc5d0":231,"\ud2b8\ub808\uc774\uc5d0":232,"\ud2b9\uc815":[17,23,29,45,48,227,228,232],"\ud2b9\uc9d5":228,"\ud2b9\ud5c8\uad8c":231,"\ud2b9\ud5c8\uc640":231,"\ud2b9\ud788":[227,231],"\ud2c0\ub9bc":22,"\ud2f1":[17,45],"\ud2f1\ub9cc\ud07c":17,"\ud30c\ub77c\ubbf8\ud130":[23,45],"\ud30c\ub77c\ubbf8\ud130\ub97c":[45,48,230],"\ud30c\ub77c\ubbf8\ud130\uc640":[45,48],"\ud30c\uc0dd\uc0c1\ud488":23,"\ud30c\uc0dd\uc794\uace0":231,"\ud30c\uc2f1\ud558\ub294":228,"\ud30c\uc545\ud558\uace0":228,"\ud30c\uc774\uc36c":232,"\ud30c\uc77c":[29,227,232],"\ud30c\uc77c\ub4e4\uc744":[227,231],"\ud30c\uc77c\ub4e4\uc774":227,"\ud30c\uc77c\ub85c":17,"\ud30c\uc77c\uc5d0":17,"\ud30c\uc77c\uc744":[29,232],"\ud30c\uc77c\uc758":[29,230],"\ud30c\uc77c\uc774":29,"\ud310\ub2e8\ud558\uace0":228,"\ud310\ub9e4":228,"\ud314\uace0":228,"\ud31d\uc5c5\ub418\ub294":228,"\ud328\ub9ac\ud2f0":230,"\ud328\uce58\ub41c":227,"\ud328\ud0a4\uc9c0":231,"\ud328\ud0a4\uc9c0\ub294":231,"\ud328\ud134\ub4e4\uc5d0":232,"\ud328\ud134\uc758":232,"\ud328\ud134\uc774":232,"\ud398\uc774\uc9c0\ub97c":227,"\ud398\uc774\uc9c0\uc5d0":228,"\ud398\uc774\uc9c0\uc5d0\uc11c":228,"\ud398\uc774\uc9c0\uc5d0\uc11c\ub294":228,"\ud3b8\uc758\ub97c":230,"\ud3b8\uc758\ud568\uc218\uac00":230,"\ud3b8\uc785":[23,230],"\ud3b8\uc785\ub418\uac70\ub098":23,"\ud3b8\uc785\ub418\uc5c8\ub2e4\uac00":23,"\ud3b8\uc785\ub41c":23,"\ud3b8\uc9d1\ub41c":230,"\ud3b8\uc9d1\ud558\uace0":230,"\ud3b8\uc9d1\ud574\uc8fc\uc5b4\uc57c":230,"\ud3b8\ud560\ubc95\ud55c":227,"\ud3c9\uac00":45,"\ud3ec\uae30\ud588\ub2e4":228,"\ud3ec\ub9f7":231,"\ud3ec\ub9f7\uc740":232,"\ud3ec\ub9f7\uc785\ub2c8\ub2e4":232,"\ud3ec\ud138\uc758":228,"\ud3ec\ud568":[17,30,228],"\ud3ec\ud568\ub418\ub294":48,"\ud3ec\ud568\ub418\ub294\ub370":[27,56],"\ud3ec\ud568\ub41c":[23,28,29,45],"\ud3ec\ud568\ub429\ub2c8\ub2e4":30,"\ud3ec\ud568\uc2dc\ucf1c":231,"\ud3ec\ud568\uc2dc\ud0a4\uace0":29,"\ud3ec\ud568\uc73c\ub85c":17,"\ud3ec\ud568\ud558\ub294":[228,231,232],"\ud3ec\ud568\ud558\ub3c4\ub85d":17,"\ud3ec\ud568\ud55c":228,"\ud3ed\uc99d\ud558\ub294":[45,48],"\ud3f4\ub354":[231,232],"\ud3f4\ub354\uc5d0":17,"\ud3f4\ub354\uc5d0\uc11c\ub3c4":231,"\ud3f4\ub354\uc758":231,"\ud45c\uba74\uc801\uc73c\ub85c":228,"\ud45c\uc2dc\ud558\uac8c\ub054":232,"\ud45c\uc2dc\ud569\ub2c8\ub2e4":29,"\ud45c\uc900\uc5d0\uc11c":228,"\ud480\uc5b4\ubd24\uc73c\uba74":228,"\ud48b":17,"\ud48b\uc635\uc158":17,"\ud48d\ubd80\ud574":228,"\ud504\ub85c\uadf8\ub798\ubc0d\uc5d0":231,"\ud504\ub85c\uadf8\ub798\ubc0d\uc740":231,"\ud504\ub85c\uadf8\ub798\ubc0d\uc774":231,"\ud504\ub85c\uadf8\ub798\ubc0d\uc801\uc73c\ub85c":231,"\ud504\ub85c\uadf8\ub7a8":[17,227,230],"\ud504\ub85c\uadf8\ub7a8\ub4e4\uc744":228,"\ud504\ub85c\uadf8\ub7a8\ub9e4\ub9e4":231,"\ud504\ub85c\uadf8\ub7a8\ub9e4\ub9e4\ucd94\uc774\uc694\uccad":231,"\ud504\ub85c\uadf8\ub7a8\uc5d0":232,"\ud504\ub85c\uadf8\ub7a8\uc5d0\uc11c":230,"\ud504\ub85c\uadf8\ub7a8\uc740":232,"\ud504\ub85c\uadf8\ub7a8\uc744":[227,228,230,232],"\ud504\ub85c\uadf8\ub7a8\uc758":232,"\ud504\ub85c\uadf8\ub7a8\uc774":[228,232],"\ud504\ub85c\uc138\uc2a4":29,"\ud504\ub85c\uc138\uc2a4\uac00":[231,232],"\ud504\ub85c\uc138\uc2a4\ub85c":232,"\ud504\ub85c\uc138\uc2a4\ub97c":232,"\ud504\ub85c\uc81d\ud2b8":231,"\ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c":232,"\ud504\ub85c\ud1a0\ud0c0\uc785":231,"\ud504\ub85c\ud1a0\ud0c0\uc785\uc5d0\uc11c":231,"\ud504\ub85c\ud1a0\ud0c0\uc785\uc744":231,"\ud504\ub85c\ud1a0\ud0c0\uc785\uc774":231,"\ud504\ub86c\ud504\ud2b8\uac00":227,"\ud504\ub86c\ud504\ud2b8\uc5d0":227,"\ud504\ub9ac\ubcf4\ub4dc":3,"\ud50c\ub798\uadf8\ub97c":29,"\ud50c\ub7ec\uc2a4":5,"\ud544\uc218\uac00":228,"\ud544\uc218\ub85c":227,"\ud544\uc694":[45,228,231],"\ud544\uc694\uac00":228,"\ud544\uc694\ub294":[227,232],"\ud544\uc694\uc131\uc5d0":231,"\ud544\uc694\uc5c6\ub2e4":228,"\ud544\uc694\uc5c6\uc9c0\ub9cc":228,"\ud544\uc694\uc5d0":45,"\ud544\uc694\ud558\ub2e4":[228,230],"\ud544\uc694\ud558\ub2e4\uba74":[45,48,228,230,231],"\ud544\uc694\ud558\uc9c0":228,"\ud544\uc694\ud55c":[17,228,230,232],"\ud544\uc694\ud560":[17,227,228,232],"\ud544\uc694\ud560\ub54c\ub9c8\ub2e4":228,"\ud544\uc694\ud568":231,"\ud544\uc694\ud569\ub2c8\ub2e4":[48,227,231,232],"\ud544\uc790\ub294":228,"\ud558\uac8c":[17,228],"\ud558\uace0":[17,228,231,232],"\ud558\uae30":[17,228,231],"\ud558\ub098":231,"\ud558\ub098\ub294":[17,228],"\ud558\ub098\ub97c":[228,231],"\ud558\ub098\uc529":[17,231],"\ud558\ub098\uc529\uc758":231,"\ud558\ub098\uc5d0":231,"\ud558\ub098\uc758":[17,29,228],"\ud558\ub098\uc785\ub2c8\ub2e4":[227,231],"\ud558\ub098\uc9c0":228,"\ud558\ub294":[17,48,227,228,231,232],"\ud558\ub294\uac83\uc774":230,"\ud558\ub294\uac8c":228,"\ud558\ub294\ub370":228,"\ud558\ub294\ub370\uc694":231,"\ud558\ub2e4":228,"\ud558\ub2e8":232,"\ud558\ub2e8\uc73c\ub85c":227,"\ud558\ub2e8\uc758":227,"\ud558\ub4dc\ucf54\ub529":231,"\ud558\ub4dc\ucf54\ub529\ud560":231,"\ud558\ub8e8":228,"\ud558\uba74":[17,227,228],"\ud558\ubbc0\ub85c":17,"\ud558\uc2e4":232,"\ud558\uc600\uc73c\uba70":231,"\ud558\uc704":232,"\ud558\uc704\uc758":231,"\ud558\uc774\uc5bc\ud380\ub4dc":[125,131,134],"\ud558\uc774\uc77c\ub4dc\ud380\ub4dc":17,"\ud558\uc774\ud37c\ub9c1\ud06c\ub85c":228,"\ud558\uc790\uba74":228,"\ud558\uc9c0":[29,45,228],"\ud558\uc9c0\ub9cc":228,"\ud558\ud55c\uac00":[230,231,232],"\ud55c":[17,227,228],"\ud55c\uacb0":228,"\ud55c\uacc4\uac00":231,"\ud55c\uacc4\uc810\uc740":228,"\ud55c\uad6d\uac70\ub798\uc18c":228,"\ud55c\uad6d\ub2e8\uc790":230,"\ud55c\uad6d\uc54c\ucf5c":230,"\ud55c\uad6d\uc564\ucef4\ud37c\ub2c8":[230,231],"\ud55c\uad6d\uce74\ubcf8":230,"\ud55c\uad6d\ucf5c\ub9c8":230,"\ud55c\uad6d\ud0c0\uc774\uc5b4\uc564\ud14c\ud06c\ub180\ub85c\uc9c0":230,"\ud55c\uae00":17,"\ud55c\uae00\uacfc\ucef4\ud4e8\ud130":230,"\ud55c\uae00\uba85":17,"\ud55c\uae00\uba85\uc744":17,"\ud55c\ub2e4":[17,228,230],"\ud55c\ubc88":[227,228,230],"\ud55c\ubc88\uc5d0":[17,228],"\ud55c\ubc88\uc740":17,"\ud55c\uc12c":230,"\ud55c\uc77c\uc2dc\uba58\ud2b8":[230,231],"\ud55c\uc77c\ud604\ub300\uc2dc\uba58\ud2b8":230,"\ud55c\uc815\ud574\uc11c":230,"\ud560":[17,227,228,231,232],"\ud560\uac83\uc778\uc9c0":17,"\ud568\uaed8":[17,29],"\ud568\uc218":[17,23,29,45,48,230,232],"\ud568\uc218\uac00":230,"\ud568\uc218\ub0b4\uc5d0\uc11c":[29,230,231],"\ud568\uc218\ub294":[17,48,230,231,232],"\ud568\uc218\ub4e4":232,"\ud568\uc218\ub4e4\ub3c4":232,"\ud568\uc218\ub4e4\uc5d0":231,"\ud568\uc218\ub4e4\uc740":232,"\ud568\uc218\ub4e4\uc744":[45,231,232],"\ud568\uc218\ub4e4\uc774":232,"\ud568\uc218\ub85c":[17,23,230],"\ud568\uc218\ub97c":[17,23,29,45,48,230,231,232],"\ud568\uc218\ubc18\ud658\uac12\uc740":17,"\ud568\uc218\ubcc4":231,"\ud568\uc218\uc5d0":231,"\ud568\uc218\uc5d0\uc11c":[45,48,230,231],"\ud568\uc218\uc600\ub358":231,"\ud568\uc218\uc758":[17,45,48,230,231],"\ud568\uc218\uc774\ub984":17,"\ud568\uc218\uc774\uba70":17,"\ud568\uc218\uc778\uc790\ub85c":17,"\ud568\uc218\uc785\ub2c8\ub2e4":[17,45],"\ud568\uc218\uc785\ub825\uac12":22,"\ud568\uc218\ucf5c\uc5d0":232,"\ud568\uc218\ud638\ucd9c\uc2dc":17,"\ud569":17,"\ud569\ub2c8\ub2e4":[17,29,45,48,227,231,232],"\ud569\ub9ac\uc801\uc73c\ub85c":228,"\ud569\uc0b0":45,"\ud569\uc0b0\ud574\uc11c":30,"\ud569\uc131\uc12c\uc720":17,"\ud569\uccd0\uc9c0\ub294":232,"\ud56d\ubaa9":228,"\ud56d\ubaa9\ub2f9":17,"\ud56d\ubaa9\ubcc4":23,"\ud56d\ubaa9\uc120\ud0dd":228,"\ud56d\ubaa9\uc774":17,"\ud574":227,"\ud574\uacb0\ub418\uba70":231,"\ud574\uacb0\ud558\uc5ec":231,"\ud574\uacb0\ud569\ub2c8\ub2e4":29,"\ud574\uacb0\ud588\uc2b5\ub2c8\ub2e4":231,"\ud574\ub193\ub294":232,"\ud574\ub2f9":[17,29,45,48,227,228,230,231,232],"\ud574\ub2f9\ub418\ub294":17,"\ud574\ub2f9\ub418\ub294\ub370\uc694":231,"\ud574\ub2f9\ub418\uc5b4":228,"\ud574\ub2f9\ub429\ub2c8\ub2e4":231,"\ud574\ub2f9\uc5c6\uc74c":[17,29],"\ud574\ub2f9\uc870\uac74\uc740":30,"\ud574\ub2f9\uc885\ubaa9\uc5d0\ub300\ud55c":17,"\ud574\ub2f9\ud558\ub294":[17,23,29,45,48],"\ud574\ub2f9\ud558\uba70":232,"\ud574\ub3c4":228,"\ud574\ubcf4\uace0":228,"\ud574\ubcfc":[228,230],"\ud574\uc11c":[227,228,230,232],"\ud574\uc18c\ud558\uae30":231,"\ud574\uc57c":48,"\ud574\uc678":228,"\ud574\uc678\ub9ac\uc5bc\uc794\uace0":231,"\ud574\uc678\uc2dc\uc138":231,"\ud574\uc678\uc2e4\uc2dc\uac04\uc794\uace0\uc870\ud68c":231,"\ud574\uc678\uc794\uace0":231,"\ud574\uc678\uc794\uace0\ucd1d\ud569":231,"\ud574\uc678\uc8fc\ubb38\uccb4\uacb0":231,"\ud574\uc678\uc8fc\uc2dd\uc8fc\ubb38":231,"\ud574\uc678\uc8fc\uc2dd\uccb4\uacb0":231,"\ud574\uc678openapi":86,"\ud574\uc81c":[17,22],"\ud574\uc81c\ud558\uace0":232,"\ud574\uc81c\ud558\ub294":[45,48],"\ud574\uc81c\ud558\ub3c4\ub85d":[45,48],"\ud574\uc81c\ud569\ub2c8\ub2e4":29,"\ud574\uc8fc\ub294":232,"\ud574\uc918\uc57c":228,"\ud574\uc9c0":17,"\ud574\uc9c0\ub418\uace0":17,"\ud574\uc9c0\ub418\uc9c0":17,"\ud574\uc9c0\ub428":17,"\ud574\uc9c0\ub97c":48,"\ud574\uc9c0\ud558\uace0":17,"\ud575\uc2ec":231,"\ud578\ub4e4\ub7ec":[45,48],"\ud578\ub4e4\ub7ec\uac00":48,"\ud588\uc2b5\ub2c8\ub2e4":231,"\ud588\uc744":231,"\ud589\uc0ac\uac00":17,"\ud589\uc0ac\uac00\uac04":17,"\ud589\uc0ac\uac00\ub9cc":17,"\ud589\uc0ac\uac00\uc5d0":17,"\ud589\uc0ac\uac00\uc640":17,"\ud589\uc0ac\uac00\uc758":17,"\ud5c8\uac00":231,"\ud5c8\uac00\uc870\ud56d\uc774":231,"\ud5ec\ud37c":17,"\ud604\ub300\ud648\uc1fc\ud551":230,"\ud604\ubb3c\uc794\uace0":231,"\ud604\uc0c1\uc774":17,"\ud604\uc7ac":[17,45,48,227,228,230,231,232],"\ud604\uc7ac\uac00":[17,228,230,231,232],"\ud604\uc7ac\uac001":17,"\ud604\uc7ac\uac002":17,"\ud604\uc7ac\uac00\ub97c":[17,29,232],"\ud604\uc7ac\uac00n":17,"\ud604\uc7ac\ub294":231,"\ud604\uc7ac\uc758":228,"\ud604\ud669":45,"\ud615\uad6d\uc73c\ub85c":228,"\ud615\uc2dd":45,"\ud615\uc2dd\uc73c\ub85c":17,"\ud615\uc2dd\uc785\ub2c8\ub2e4":17,"\ud615\uc744":17,"\ud615\ud0dc":231,"\ud615\ud0dc\ub294":230,"\ud615\ud0dc\ub85c":[29,45,228,230,231],"\ud615\ud0dc\ub85c\uc11c":231,"\ud615\ud0dc\uc758":[228,230,231],"\ud638\uac00\uad6c\ubd84":[17,45],"\ud638\uac00\uc2dc\uac04":230,"\ud638\uac00\uc815\ubcf4\ub97c":45,"\ud638\ucd9c":[17,29,45,48,230,231,232],"\ud638\ucd9c\uacb0\uacfc":23,"\ud638\ucd9c\uacb0\uacfc\ub294":17,"\ud638\ucd9c\uacb0\uacfc\ub97c":[45,48],"\ud638\ucd9c\uacfc":231,"\ud638\ucd9c\ub429\ub2c8\ub2e4":[45,48],"\ud638\ucd9c\ub9c8\ub2e4":228,"\ud638\ucd9c\ubcf4\ub2e8":231,"\ud638\ucd9c\uc2dc":[45,48,230,232],"\ud638\ucd9c\uc2dc\uc5d0":228,"\ud638\ucd9c\uc744":[29,45,48,231],"\ud638\ucd9c\uc774":[45,48,228,231],"\ud638\ucd9c\uc81c\ud55c":[45,48],"\ud638\ucd9c\uc81c\ud55c\uc744":45,"\ud638\ucd9c\ud558\uac8c":230,"\ud638\ucd9c\ud558\uace0":[45,48,232],"\ud638\ucd9c\ud558\uace0\uc790":231,"\ud638\ucd9c\ud558\uae30":17,"\ud638\ucd9c\ud558\ub294":[228,231],"\ud638\ucd9c\ud558\ub824\uba74":231,"\ud638\ucd9c\ud55c":232,"\ud638\ucd9c\ud55c\ub2e4":230,"\ud638\ucd9c\ud568":232,"\ud638\ucd9c\ud569\ub2c8\ub2e4":[29,45,48],"\ud638\ucd9c\ud574\uc57c":17,"\ud639\uc2dc\ub098":[227,228,231,232],"\ud639\uc740":[17,29,45,48,227,228,231,232],"\ud63c\uc790":228,"\ud648":232,"\ud64d\ucf69\ub2e8\uc77c\uac00\uc2dc\uc138":231,"\ud64d\ucf69\uc2dc\uc138":231,"\ud64d\ucf69\uc2e4\uc2dc\uac04\uc0c1\ud558\ud55c\uac00":231,"\ud64d\ucf69\uc5c5\uc885\uc9c0\uc218":231,"\ud64d\ucf69\uccb4\uacb0":231,"\ud64d\ucf69\ud638\uac00\uc794\ub7c9":231,"\ud654\uba74":17,"\ud654\uba74\ubc88\ud638":[17,23,27,45,56,230,231],"\ud654\uba74\ubc88\ud638\ub85c":17,"\ud654\uba74\ubc88\ud638\ub97c":17,"\ud654\uba74\ubc88\ud638\uc5d0":230,"\ud654\uba74\ubc88\ud638\uc640":17,"\ud654\uba74\uc5d0":[230,231],"\ud654\uba74\uc5d0\uc11c":[17,227],"\ud654\uba74\uc744":17,"\ud654\uba74\uc758":227,"\ud654\uba74\uc774":232,"\ud654\uba74\uc774\uc5ec\uc57c":17,"\ud655\ubcf4":228,"\ud655\ubcf4\uc758":228,"\ud655\ubcf4\ud558\ub294":228,"\ud655\ubcf4\ud558\ub824\ub294":228,"\ud655\ubcf4\ud574\uc57c\ud560\uc9c0":228,"\ud655\ubcf4\ud588\ub2e4\uba74":227,"\ud655\uc5f0\ud558\uac8c":228,"\ud655\uc778":[17,29,45,48,227,228,230,232],"\ud655\uc778\ub418\ub294":228,"\ud655\uc778\ub418\uc5c8\ub2e4":228,"\ud655\uc778\ub41c\ub2e4":228,"\ud655\uc778\uc2dc":29,"\ud655\uc778\uc744":[228,232],"\ud655\uc778\uc774":[228,230],"\ud655\uc778\ud558\uac70\ub098":29,"\ud655\uc778\ud558\uace0":[29,228,230,231,232],"\ud655\uc778\ud558\uae30":232,"\ud655\uc778\ud558\ub294":[23,231],"\ud655\uc778\ud558\uc138\uc694":227,"\ud655\uc778\ud558\uc2e0":232,"\ud655\uc778\ud55c\ub2e4":[228,230],"\ud655\uc778\ud560":[17,228,230,232],"\ud655\uc778\ud569\ub2c8\ub2e4":29,"\ud655\uc778\ud574":[29,228,231],"\ud655\uc778\ud574\uac00\uba74\uc11c":231,"\ud655\uc778\ud574\ubcf4\ub294\uac8c":228,"\ud655\uc778\ud574\ubcf4\uc790":[228,230],"\ud655\uc778\ud574\ubcf4\uc790\uba74":228,"\ud655\uc778\ud574\ubcf8\ub2e4":230,"\ud655\uc778\ud574\ubd05\ub2c8\ub2e4":227,"\ud655\uc778\ud574\ubd24\ub2e4":228,"\ud655\uc778\ud574\uc11c":231,"\ud655\uc778\ud574\uc8fc\uc2dc\uae30":23,"\ud655\uc778\ud588\ub2e4":228,"\ud655\uc778\ud588\ub358":228,"\ud655\uc7a5\uc131\uc744":231,"\ud655\uc7a5\uc774":[231,232],"\ud658\uacbd":227,"\ud658\uacbd\ub9cc":[227,231],"\ud658\uacbd\uc5d0":231,"\ud658\uacbd\uc5d0\ub294":227,"\ud658\uacbd\uc5d0\uc11c":227,"\ud658\uacbd\uc5d0\uc11c\ub9cc":[29,227,228],"\ud658\uacbd\uc5d0\uc11c\uc758":227,"\ud658\uacbd\uc73c\ub85c":227,"\ud658\uacbd\uc744":[227,231],"\ud658\uacbd\uc774":[227,228],"\ud658\uacbd\uc774\ub77c\ub294":227,"\ud658\uacbd\ud558\uc5d0\uc11c":231,"\ud658\ub960":231,"\ud65c\uc6a9":[45,48,228,230,231],"\ud65c\uc6a9\ub420":227,"\ud65c\uc6a9\uc5d0":231,"\ud65c\uc6a9\uc774":231,"\ud65c\uc6a9\ud558\uac70\ub098":230,"\ud65c\uc6a9\ud558\uace0":228,"\ud65c\uc6a9\ud558\ub294":[231,232],"\ud65c\uc6a9\ud558\ub294\ub370":[227,231],"\ud65c\uc6a9\ud558\uba74":[230,231],"\ud65c\uc6a9\ud558\uc2dc\ub294":231,"\ud65c\uc6a9\ud558\uc2dc\uba74":232,"\ud65c\uc6a9\ud558\uc5ec":[230,231],"\ud65c\uc6a9\ud55c":[45,228],"\ud65c\uc6a9\ud55c\ub2e4":228,"\ud65c\uc6a9\ud560":[227,228,231],"\ud65c\uc6a9\ud574":[227,228,231,232],"\ud65c\uc6a9\ud574\ubcfc":228,"\ud65c\uc6a9\ud574\uc11c":227,"\ud65c\uc6a9\ud574\uc57c":231,"\ud68c\uc0ac\uc5d0\uc11c":228,"\ud68c\uc6d0\uc0ac":17,"\ud68c\uc6d0\uc0ac\uba85":17,"\ud68c\uc6d0\uc0ac\ucf54\ub4dc":17,"\ud68c\ud53c":[29,231],"\ud68c\ud53c\ub97c":[45,48],"\ud68c\ud53c\ud558\uae30":[45,230],"\ud68d\ub4dd":17,"\ud69f\uc218":[29,231],"\ud69f\uc218\uc758":228,"\ud6a8\uc728\uc131":228,"\ud6a8\uc728\uc131\uc740":228,"\ud6a8\uc728\uc801\uc73c\ub85c":228,"\ud6c4":[17,23,27,29,56,227,228,232],"\ud6c4\uac15\ud241\ub2e8\uc77c\uac00\uc2dc\uc138":231,"\ud6c4\uac15\ud241\uc2dc\uc138":231,"\ud6c4\uac15\ud241\uc5c5\uc885\uc9c0\uc218":231,"\ud6c4\uac15\ud241\uccb4\uacb0":231,"\ud6c4\uac15\ud241\ud638\uac00\uc794\ub7c9":231,"\ud6c4\uc5d0":17,"\ud6c4\ucc98\ub9ac":227,"\ud6e8\uc52c":228,"\ud720\ub77c\ud640\ub529\uc2a4":230,"\ud734\uba3c\uc5d0\ub7ec":231,"\ud734\uc7a5\uc77c":231,"\ud750\ub984\uc73c\ub85c":232,"\ud750\ub984\uc774\uace0":231,"a\uc885\ubaa9\uc5d0":17,"a\uc885\ubaa9\uc758":17,"abstract":[19,25,33,78,81,88,98,150,168,169,195,203],"atm\uc744":17,"boolean":151,"case":[50,132,151,219],"cfd\ub9ac\uc5bc\uc794\uace0":231,"cfd\ub9ac\uc5bc\uc794\uace0\ucd1d\ud569":231,"cfd\ub9c8\uc9c4\ucf5c\uacbd\uace0":231,"cfd\uc785\ucd9c\uace0":231,"cfd\uc8fc\ubb38":231,"cfd\uc8fc\ubb38\uccb4\uacb0":231,"cfd\uccb4\uacb0":231,"class":[4,22,86,228,231],"cme\ubbf8\uacb0\uc81c\uc57d\uc815":231,"cme\ubbf8\uccb4\uacb0":231,"cme\ubc30\uce58":231,"cme\uc2dc\uc138":231,"cme\uc2e4\uc2dc\uac04\uc794\uace0":231,"cme\uc794\uace0\ud569":231,"cme\ud638\uac00\uc794\ub7c9":231,"const":[231,232],"default":[4,19,22,31,33,76,77,86,99,132,151,219,227,232],"dl\uac74\uc124":[230,231],"do":[50,132,219],"ecn\uc8fc\uc2dd\ub2f9\uc77c\uac70\ub798\uc6d0":231,"ecn\uc8fc\uc2dd\uc2dc\uac04\uc678\ud638\uac00":231,"ecn\uc8fc\uc2dd\uc2dc\uc138":231,"ecn\uc8fc\uc2dd\uc6b0\uc120\ud638\uac00":231,"ecn\uc8fc\uc2dd\uccb4\uacb0":231,"ecn\uc8fc\uc2dd\ud638\uac00\uc794\ub7c9":231,"elw\ub9cc\uae30\uc77c":[230,231],"elw\ud589\uc0ac\uac00":230,"enum":[67,68],"etf\uac00":[17,29],"euf\uc2dc\uc138":231,"euf\ud638\uac00\uc794\ub7c9":231,"eurex\ubc30\uce58":231,"eurex\uc2dc\uc138":231,"eurex\uc8fc\ubb38":231,"eurex\uccb4\uacb0":231,"eurex\ud638\uac00":231,"f\ud640\ub529\uc2a4":230,"fid\uac2f\uc218\ub294":17,"fid\uc218":22,"function":[18,26,34,98,150,219,224],"hdc\ud604\ub300\uc0b0\uc5c5\uac1c\ubc1c":[230,231],"hts\uc758":17,"id\ub97c":17,"import":[168,169,219,228,230,231,232],"input\uac12\uc744":17,"int":[17,22,23,29,31,32,35,45,50,67,171,219,228,231,232],"ko\uc811\uadfc\ub3c4":230,"kr\ubaa8\ud130\uc2a4":231,"long":17,"nerrcode\uac00":23,"new":[67,68,81,98,168,219,224,228,230],"nhn\uc5d4\ud130\ud14c\uc778\uba3c\ud2b8":228,"output\uc744":17,"public":[18,26,34,93],"ray\uc21c\uac04\uccb4\uacb0\ub7c9":231,"request\uc758":4,"return":[17,18,19,23,26,33,34,50,78,93,99,102,168,203,205,219,228,230,231],"sk\ucf00\ubbf8\uce7c":[230,231],"snt\ubaa8\ud2f0\ube0c":230,"srqname\uacfc":23,"sscrno\uc640":23,"static":[13,32,50,224],"strcode\uacfc":23,"super":[98,231],"tr\ub9c8\ub2e4":17,"tr\ubaa9\ub85d\uc5d0\uc11c":17,"tr\ubcc4":17,"tr\uc5d0":17,"tr\uc5d0\uc11c":17,"tr\uc740":17,"tr\uc758":17,"tr\uc774\ub984":[27,56],"tr\uc870\ud68c\ub85c":17,"tr\ucf54\ub4dc":17,"true":[29,32,35,45,77,78,80,81,82,96,97,100,101,151,176,177,179,203,209,219,222,228,230,231,232],"try":[19,33,230,231],"ts\uace0\uc800\ubcc0\uacbd":231,"ts\ubcc0\uacbd":231,"vi\ubc1c\ub3d9":231,"vi\uc815\uc801\uc608\uc0c1\uac00":231,"while":230,A:[17,18,19,26,33,34,78,93,192,203,219,224],By:132,For:[19,33,151],If:[18,26,34,78,93,99,151,203,219,224],In:[228,230],It:[18,26,34,78,93,168,203],No:228,Not:231,OR:231,Or:224,Such:219,The:[18,26,34,81,93,98,132,151,219,224],Then:224,To:224,__class__:96,__file__:232,__getitem__:[19,33],__init__:[228,231],__main__:231,__name__:231,_bld:228,_calendar:228,_datalength:[27,51,53,56],_delist:228,_download:228,_engin:228,_errorcod:[27,51,53,56],_header:228,_inspector:228,_messag:[27,51,53,56],_multithreadedrendezv:230,_postgresql:219,_splmmsg:[27,51,53,56],_stock:228,_stocks_delist:228,_type:219,a000660:17,a005930:[17,228,230],a021:93,a035420:228,a1574a0d:[28,232],a3af:90,a979:93,abc:[71,98,168,169,195],about:224,abov:[50,219,224],acc:16,acc_trdval:228,acc_trdvol:228,accept:[18,26,34,93,151],acclist:17,accno:17,account:[45,99,117,118,120,125,232],account_cnt:17,account_data:[1,125,137,152],account_deposit:231,account_evalu:231,account_evaluation_per_stock:231,account_evaluation_summari:231,account_list:231,account_no:[45,152,230,231],account_password:[29,230,232],account_tmout:99,account_window:[1,137,143,152],ack:[48,50],act:[98,132,151],action:224,activ:227,actual:[50,132,151],ad:219,add:[219,224],add_call_histori:[30,201,203],add_callback:[24,87],add_cybosplusproxyserviceservicer_to_serv:13,add_kiwoomopenapiplusserviceservicer_to_serv:50,add_order_histori:96,add_to_pars:151,adddata_fromfil:[100,101],addit:[50,219],addpric:17,addpricetoconditionsearchresult:29,adj:228,adjclos:228,adjust_data:[176,179],adjust_pric:228,adjust_ratio:228,adjusted_minutes_data:228,adjusted_pric:[3,45,228,230],adjustement_onli:3,adjustment_ratio:228,after:[50,78,182,203,231],agent:228,all:[4,17,22,78,81,86,98,99,131,134,151,203,219,224,228],all_symbol:209,allow:219,allow_from_autoenv:151,allow_magic_lookup:76,also:[50,98,219],altern:219,alternative_dns_nam:113,alwai:224,amd64:227,amount:[100,101,228],amp:230,an:[18,26,34,50,78,81,93,98,99,151,203,219,224,230,232],anaconda3:227,analysi:224,ananconda:227,ani:[19,29,33,35,50,78,171,203,219,224],annot:[18,26,34,93],anyth:[168,219,224],api:[99,226,228,231,232],api_module_path:37,api_module_path_from_default_instal:37,api_module_path_from_typelib_dl:37,apimodulepath:232,app:[66,69,231,232],append:[228,230,231,232],applewebkit:228,applic:[230,232],appreci:224,appropri:192,ar:[18,26,34,50,93,125,131,134,151,219,224],arbitrari:[50,151],architectur:228,arg:[4,18,19,22,24,26,30,33,34,45,67,68,78,86,87,90,92,93,96,97,99,141,147,148,150,152,159,173,187,188,189,190,201,203,207,209,219,222,223,224,232],argpars:[67,68,150],argument:[12,18,26,34,46,49,50,78,93,99,151,203,230,231],argumentdecor:150,argumentpars:[67,68,150],arguments_messag:46,argv:[231,232],arithmet:219,arrai:228,articl:224,as_of:209,as_summari:[118,125],ascend:228,asctim:230,aspx:5,assert:[228,231],asset_typ:45,assignprimit:10,associ:[11,13,50,78,203,219],assum:219,astimezon:[228,230],astyp:228,asutc:97,async_cal:[19,203],asynchron:[78,203],atm:17,atomiccommrqdata:29,attempt:219,attr:151,attribut:[18,26,219],augment:219,authority_cert_filenam:113,authority_key_filenam:113,authority_key_password:113,auto:[1,151,226],auto_login:[1,109,111,137,152],autoapi:1,automat:[151,224],await_handl:53,axi:[228,231],b:224,backend:[1,99,172,230,232],backfil:97,backfill_start:97,backtrad:[1,172,231],bar:228,base:[1,2,3,4,5,8,11,13,18,19,20,22,24,26,27,28,29,30,31,32,33,34,35,38,45,47,48,50,51,52,53,54,55,56,57,58,59,60,66,67,68,69,71,76,77,78,80,81,82,86,87,89,90,92,93,96,97,98,99,100,101,102,103,104,105,132,150,151,168,169,183,185,187,188,189,190,192,194,195,201,203,210,214,216,217,218,219,220,221,222,227],basic:232,basicconfig:230,been:[78,203],befor:224,behavior:[18,26,34,93,219],being:[50,219],below:[219,224],best:224,bidirect:50,bidirectionallisten:[48,50],bidirectionallistenrequest:49,bidirectionalrealcal:[48,50],bidirectionalrealinitializerequest:49,bidirectionalrealregisterrequest:49,bidirectionalrealremoverequest:49,bidirectionalrealrequest:49,bidirectionalrealstoprequest:49,bin:227,binaryio:31,bind:[18,26,34,93,219],bind_dynamic_call_arg:19,bind_parti:[18,26,34,93],bit:[224,227],black:224,blank:218,bld:228,bldattend:228,blob:3,block1:228,block:[80,81,82,218],blockrequest2:4,blockrequest:4,blog:224,bnext:17,boardseq:5,bodi:66,bond_onli:[120,125],bool:[19,22,29,32,33,35,66,67,76,171,181,203],boolcompat:22,borrow_screen:32,bound:219,boundargu:[18,26,34,93],bp:[230,231,232],branch:224,broker:99,broker_thread:99,brokerbas:96,brokercl:99,browser:228,bstr:[27,56],btn1:231,btn1_click:231,btn2:231,btn2_click:231,buffer:[12,49],bufferedqueueiter:[80,81,82],bugfix:224,bui:[50,96,230],build:232,buildoleitem:[93,200],built:[98,99,219],builtin:[1,172,183],bump2vers:224,buy_onli:[120,125],bytesio:228,c769dc00f6f7:230,c79de781363d:93,c9e98344e17a:90,c:[28,171,219,230,232],cach:219,cache_ok:219,caches:102,calendar:[102,181,230],call:[19,33,45,48,50,78,92,201,203,219,230],call_credenti:[13,50],callabl:[19,22,29,33,78,98,203],callablereturnsint:22,callablereturnsintorbool:22,callandlistenrequest:49,callandlistenrespons:49,callback:[24,29,44,50,87,151],callrequest:49,callrespons:49,can:[19,33,50,78,98,132,151,203,219,224],cancel:[19,50,96,203,230,231],cancel_aft:[182,231],cancel_futur:[78,203],candl:99,cannot:230,capabl:50,capit:151,categor:50,caus:219,cd:[224,231],cerebro:[100,101],cert_filenam:113,cert_password:[230,232],certain:[50,219],certpassword:232,chang:[151,219,224,228],changeev:[28,90],changer:228,channel:[13,50],channel_credenti:[13,50],chart_data:[1,125,137,152,231],chart_typ:3,check:[29,222,224,231],check_apply_simulation_window:38,check_code_or_rais:[4,22,86],check_return_valu:19,check_sleep_second:[30,201,203],check_timeout:42,checkout:224,chrome:228,chunk:184,ci:224,cl:[3,4,16,18,22,24,26,29,31,35,38,66,67,68,76,86,87,93,96,97,98,99,100,101,168,169,176,179,185,187,188,189,190,206,219,223],classmethod:[3,4,16,18,22,24,26,29,31,35,38,66,67,68,76,86,87,93,99,100,101,168,169,176,179,206,219,223],clean:[78,151,203],cleanup:[138,139,144,145],cli:[1,67,68,172,226],click:[151,231],clickargumentpars:150,client:[13,50,200,228,230,232],client_argument_pars:155,client_cert_file_opt:155,client_check_timeout:20,client_enable_ssl_opt:155,client_host_opt:155,client_key_file_opt:155,client_opt:155,client_port_opt:155,client_root_certs_file_opt:155,clone:[96,224,227,231],close:[20,24,42,67,87,98,99,102,192,228,230,231],close_cli:20,close_ord:99,close_server_proc:20,closeev:[28,90],clsid:[28,90,93],clsname:[97,98,99,185,187,188,189,190],cmd:[222,228],cme:231,cmpprevdd_prc:228,cmpprvdd_prc:228,co:228,co_varnam:[18,26,34,93],code:[3,4,12,18,22,25,26,27,29,34,45,49,50,51,53,56,59,86,88,89,93,98,99,120,122,124,125,131,132,134,135,136,152,224,228,230,231,232],code_by_nam:231,code_delet:231,code_insert:231,code_list:[230,231],code_list_info:231,codelist:[1,25,27,51,53,56,125,133,137,232],codelist_interact:[1,125,133,137],codes_by_nam:230,coerc:[219,228],coerce_compared_valu:219,col:228,collect:[32,71,99],column:[219,228,230,231],column_nam:228,com:[0,3,5,224,227,228,231],combine_first:228,come:219,comm:228,comm_connect:232,comm_rate_limit:30,command:[1,150,151,152,172,224,232],commanddecor:150,commconnect:[3,17,45,48,231,232],commconnectandthen:29,comment:[11,13,50],commgetdata:17,comminfo:96,comminfobas:96,comminvestrqdata:17,commiss:96,commit:[224,231],commkwrqdata:[17,45,48],common:[4,22,86,99],common_nam:113,commrqdata:[17,23,29,45,48,50,231,232],commrqdatawithinput:29,commtermin:17,compact:171,compar:50,compat:[1,19,28,33,66,67,76,77,78,172,187,188,189,190,203,231,232],compil:219,compile_proto:[1,62,64,65],complex:50,compositetimewindowratelimit:[30,201],compress:[13,50,99],comtype_to_pythontyp:[34,93],concat:[228,231],concret:[78,98,203],concurr:[19,78,203],conda:227,conda_force_32bit:227,condit:[50,230],condition_ev:230,condition_index:[25,27,30,45,51,53,56],condition_met_code_list:231,condition_met_code_list_info:231,condition_nam:[25,27,30,45,51,53,56,230,231],condition_name_list:231,condition_typ:[25,27,51,53,56,231],conditioncal:[45,48,50],conditionrequest:49,conditionrequestflag:49,conf:[171,232],config:[1,166,172],config_from_dict:171,configur:232,confirm:151,confirmation_prompt:151,connect:[3,24,29,33,44,50,67,68,87,92,103,105,228,231,232],connect_to:[33,92],connectionstatu:[67,68],connectusingpywinauto:3,connectusingpywinauto_impl:3,connectusingpywinauto_runscriptinsubprocess:3,consecut:50,consid:[98,219],consider:50,consol:[152,232],constructor:[99,151],consume_request_iter:59,contain:[1,151],containing_oneof:[12,49],containing_typ:49,content:228,context:[11,13,48,50,51,52,53,54,55,57,58,59,60,99,151,232],context_set:152,contextlib:231,contextmanag:231,contribut:226,contributor:226,control:[19,24,27,32,33,47,48,51,52,53,54,55,56,57,58,59,60,84,87,89,92,151,231,232],control_clsid:37,control_progid:37,convert:219,convert_arguments_from_protobuf_to_python:46,convert_arguments_from_python_to_protobuf:46,convert_dtyp:228,convert_flo:228,convert_list_argu:74,convert_to_dict:98,cookiecutt:231,coordin:50,copi:219,copyleft:231,copyright:227,core:[1,7,8,15,45,52,56,65,81,95,98,99,172,232],correspond:[13,18,26,34,50,93],could:[219,224],count:[16,32,151,228],country_nam:113,cov:224,cp_luncher:3,cpdib_rtf_1_:3,cppy:3,cpsysdib_rtf_1_:3,cputil_rtf_1_:4,creat:[1,18,26,34,93,98,168,224,227,228,230,232],create_engin:228,create_job_object_for_cleanup:222,create_modul:168,create_new_vers:218,create_ord:99,create_snapshot:214,creation:219,credenti:[1,3,29,38,42,45,47,152,156,172,230,232],credit:[224,226,227],csr_filenam:113,csv:31,csvxls_isno:228,ctrl:232,ctx:[141,151,152,154,159],ctype:[1,172,183],curl:227,current:50,current_pric:231,current_working_directori:171,custom:[50,151,219],customcallandlisten:[48,50],customlisten:[48,50],cwd:[157,222],cybo:228,cybos_data:228,cybos_data_adjust:228,cybos_data_adjusted_clos:228,cybos_entrypoint:228,cybosplu:[2,3,4,228],cybosplus_interfac:4,cybosplusdispatch:2,cybosplusdispatchproxi:8,cybosplusdispatchproxymethod:8,cybosplusentrypoint:[1,6,7,15,228],cybosplusentrypointmixin:[1,2,6,7,8,15,228],cybosplusentrypointproxi:[1,7,14,15],cybospluserror:[1,6,7,15],cybosplusev:11,cybospluseventhandl:11,cybospluseventiter:11,cybosplusincompleteprogid:2,cybosplusincompleteprogidproxi:8,cybospluslookuprequestratelimit:5,cybosplusproxyservic:[1,7,13,14,15],cybosplusproxyservice_pb2:[1,7,14,15],cybosplusproxyservice_pb2_grpc:[1,7,11,14,15],cybosplusproxyservicemessageutil:[1,7,14,15],cybosplusproxyserviceservic:[1,7,13,14,15],cybosplusproxyservicestub:13,cybosplusratelimit:[1,6,7,15],cybosplusrequesterror:4,cybosplustraderequestratelimit:5,d1acab7d:90,d:[23,228,230,231],dai:[102,181,219,228],daili:[1,123,125,137,231,232],daishin:5,daishin_cybos_plu:[1,15,172],dani:0,dat:17,dat_fil:31,data:[1,29,50,96,99,172,183,207,209,211,219,226,229,230,231,232],data_adjust:230,data_dir:35,data_length:231,data_list:231,data_start:96,databas:[97,100,103,105,219],datacl:99,datafram:[45,230,231],datalength:[25,54,58,60,232],datanam:99,dataread:228,date2num:97,date:[45,120,125,219,228,230,231,232],datetim:[1,66,102,172,183,219,228,231],datetime_is_numer:228,dbm:228,dct:[96,97,98,99,185,187,188,189,190],dd8474120071:230,deactiv:227,deal:219,debug:[166,171,228,230,232],debug_error_str:230,decl:151,declar:[19,33],decor:[151,219],ded88711818d:[28,232],def:[19,33,219,228,230,231,232],default_client_host:155,default_client_port:155,default_common_host:155,default_common_port:155,default_config:171,default_config_file_directori:171,default_config_filenam:171,default_config_filepath:171,default_dispatch_class_nam:116,default_dispatch_file_path:116,default_encod:[152,171],default_event_class_nam:116,default_event_file_path:116,default_server_bind_address:155,default_server_host:155,default_server_port:155,default_user_config_filenam:171,default_user_config_filepath:171,defin:[13,19,33,50,67,68,98,132,151,219],delet:[207,209,214,216,218,220],delete_librari:[208,210],delete_snapshot:209,delpric:17,delpricefromconditionsearchresult:29,depend:[224,231],deploi:226,deposit:[1,119,125,137,232],depth:205,deriv:[67,68],desc:[31,231],descend:98,describ:228,descript:[99,224],descriptor:[12,49,77],deseri:219,desir:[50,132,219],dest:151,dest_filenam:101,destin:132,detail:[224,230],detect:151,determin:132,develop:[224,226],df:[99,228],dialect:219,dialog:[66,76],dialogtohandl:66,dic:[35,206],dict:[18,26,29,31,34,35,78,200,203,230,231],dict_records_from_datafram:99,dictionari:171,differ:219,dir_publ:173,direct:219,directli:98,dirnam:232,disabl:[1,137,152,172,228,232],disable_auto_login:152,disable_auto_login_after_login:108,disable_auto_login_without_login:108,disable_autologin:38,disableautologin:29,disconnect:[24,33,44,67,68,87,92,231,232],disconnect_from:33,disconnectrealdata:17,discord:231,discordmesseng:[1,172,183,196],discordwebhookmesseng:194,dispatch:[11,13,132],dispatch_class_nam:[40,115,116],dispatch_clsid:[37,93],dispatch_file_path:[40,115,116],dispatch_ole_item:36,dispatch_signatures_by_nam:[18,93],dispatchitem:200,dispatchrequest:12,dispatchrespons:12,distinct:50,distribut:227,dividend:228,doc:224,docstr:224,document:[1,11,13,50,231],doe:[192,219],doityourselfdiscordwebhookmesseng:194,don:[151,224],done:[11,50,224],dongyoon:0,download:[175,176,177,178,179,228],download_openapi_instal:157,driven:224,drlegal:231,drop:[228,231],dt:[97,180],dtbegin:99,dtend:99,dtype:228,dump_config:171,dump_fil:[31,35],dump_from_stor:101,dump_realtype_by_desc:31,dump_trinfo_by_cod:35,dw_basic_list:5,dynam:[50,151],dynamic_cal:19,dynamic_call_and_check:19,dynamiccal:[231,232],e5:5,e:[230,231],each:[18,26,34,50,93,219],easier:224,elbakram:[0,224,227,231],element:[81,98],eleven_dai:228,elif:[228,231],ellipsi:[19,29,33,78,203],els:[219,228,230,231,232],elw:[17,125,131,134,231],emiss:[81,98],emit:132,emitsign:77,emphasi:[18,26,34,78,93,203],empti:[18,26,34,93,99,151],empty_config:171,enabl:[1,82,137,151,152,172,232],enable_autologin:38,enable_autologin_using_pywinauto:38,enableautologin:29,enableautologinusingpywinauto:29,enableautologinusingpywinauto_impl:29,enableautologinusingpywinauto_runscriptinsubprocess:29,encod:[16,31,35,40,115,116,171,206,219],end:[18,26,34,78,81,93,98,203,218],end_dat:[3,45,122,124,125,175,177,178,179,228],end_tim:[176,179,207,209],enddd:228,engin:[101,103,105],enhanc:224,ensur:[219,232],ensureautologinen:29,ensureconditionload:[29,45,230,231],ensureconnect:[3,29,228,230,231,232],ensureconnectedandthen:29,ensurepath:[224,231],enter:[24,87],entiti:[81,98],entri:[16,93,132,224],entrypoint:[2,230,231],enum_typ:49,enumer:[67,68,230],enumerationitem:200,env:[97,227],environ:[151,226,232],envnam:171,envpath:171,ep:[230,231,232],epoch:219,equal_to:49,err:232,err_cod:[125,126,231],errcod:[25,27,53,54,56,57,58,59,60,88,89,232],errmsg:[1,125,127,137,232],error:[81,98,228,232],error_cod:231,error_messag:231,error_message_by_cod:[4,22,86],error_respons:99,errorcod:[25,54,58,60,232],etc:[19,33],etf:[17,29,125,131,134,231],etn:[17,231],euc:157,ev:[230,231,232],eval:48,evalu:[1,119,125,137,232],even:[50,98,224],event:[1,11,13,15,28,50,62,65,90,98,132,228,230,231,232],event_class_nam:[40,115,116],event_clsid:[37,93],event_file_path:[40,115,116],event_handler_signatures_by_nam:[26,93],event_nam:[28,45,90],event_ole_item:36,event_to_dict:98,eventdonerequest:12,eventfiredrespons:12,eventrequest:12,eventrespons:12,eventstartedrespons:12,eventstartrequest:12,eventstoprequest:12,everi:[219,224],ex:17,exampl:[17,19,33,219,224,231],exc_typ:[24,59,87],exc_valu:[24,59,87],except:[4,16,19,22,33,81,86,98,99,230,231],except_callback:22,exchange_calendar:[1,172,183,228,230,231],exchangecalendarstradingcalendar:102,exclud:32,exclude_delist:[118,125],exec:[48,232],exec_:[67,68,231,232],exec_modul:168,execandexit:[67,68],exectyp:96,execut:[78,203,219,222],executable_config:171,executed_onli:[120,125],executor:[44,45,78,203],exist:219,exit:[4,22,24,67,68,86,87,99,227,232],exp:16,expect:[102,219],explain:224,explicitli:50,expose_valu:151,express:219,extend:231,extens:[1,67,68,152,172],extra:151,extract:219,extractprimit:10,f04b6a919f1c:230,f9a2c4046337:230,f:[16,28,35,206,230,232],fail_with_usag:[1,152,156,172],fals:[3,13,29,40,45,50,76,78,96,97,147,151,152,153,157,166,171,176,177,179,203,209,214,218,219,228,230,231],fast_pars:[45,230,231],fdr:228,fdr_data:228,fdr_data_adjusted_clos:228,featur:[151,226],feed:[97,100,103,105],fetch:219,fid20:98,fid:[17,23,31,35,45,48,152,230,231],fid_by_fid:31,fid_by_nam:31,fid_dump_filedir:31,fid_dump_filenam:31,fid_dump_filepath:31,fid_dump_processor:31,fid_list:[59,230,231],fid_nam:231,fidlist:[25,27,53,56,58,88,89],fids_from_dump_fil:31,field:[35,50,230,231],file:[11,13,50,224,232],filenam:[100,101,104,105,171,176,177,179,207,208,210,222,228,230,232],filepath:[157,158],filter_chejan_respons:98,filter_for_cod:98,filter_price_ev:98,financ:228,financedataread:228,financi:228,financialdataread:228,find_free_port_for_host:197,find_spec:[168,169],find_user_config_file_from:171,find_user_config_file_in:171,finder:[168,169,228],finder_listdelisu:228,finder_stkisu:228,findwindow:[1,160,169,172],finish:[50,78,203],firew_secgb:17,first_account_no:[230,231],flag:[29,151,219],flag_valu:151,flake8:224,float64:228,floor:[228,230],fluc_rt:228,fluc_tp_cd:228,fn:[19,30,78,203],fok:17,follow:[18,19,26,33,34,50,93,224],foo:219,for_each:[118,125],forc:[29,45,151,232],force_overwrit:[40,115,116],fork:224,format:[122,124,125,132,135,152,192,228,230,232],formatt:[132,224],found:228,frame:77,free:231,from:[18,19,26,33,34,50,67,68,93,99,151,168,219,226,228,230,231,232],from_cod:35,from_datfil:16,from_dict:[35,206],from_encfil:35,from_fid:31,from_json:206,from_nam:[18,26,31,93],from_record:[230,231],from_titl:76,from_tupl:99,fromdat:[100,101],fromtimestamp:97,fsf:231,full_cod:228,full_verbos:159,full_verbose_opt:[141,159],fullnam:[168,169],func:[4,22,71,86,198,201,203,222],function_to_script:222,function_to_subprocess_arg:222,functionorcommand:150,functool:[1,18,26,34,93,149,152,172],fund:96,further:219,futur:[19,78,203,230],g:230,gather:50,gecko:228,gener:[1,12,19,33,49,50,67,68,137,152,172,219,228,232],generate_key_cert_signed_by_author:113,generate_python_stub:[1,39,41,65],generate_self_signed_key_cert:113,genpi:200,get:[1,137,152,172,226,229,231,232],get_32bit_execut:171,get_64bit_execut:171,get_account:99,get_adjust_ratio:[176,179,228],get_api_module_path:38,get_autologin_dat:38,get_calendar:[228,230],get_cash:99,get_class_logg:185,get_config:171,get_credenti:[147,152,153],get_error_message_by_cod:[4,22,86,231],get_executable_from_conda_envnam:171,get_executable_from_conda_envpath:171,get_executable_from_executable_config:171,get_fids_by_realtype_nam:[31,230,231],get_fids_by_realtype_name_as_str:31,get_field_names_by_realtype_nam:[31,231],get_free_localhost_port:197,get_free_screen:32,get_full_cod:[175,179,228],get_granular:99,get_grpc_stub:42,get_help:154,get_help_without_usag:154,get_histori:99,get_host:47,get_input_nam:35,get_inst:223,get_instru:99,get_instruments_origin:99,get_last_session_d:181,get_latest_vers:[214,218],get_librari:[208,210],get_limiter_per_condit:30,get_logg:[152,166,185,186],get_loglevel:[185,186],get_module_logg:185,get_multi_output_nam:35,get_multiple_free_screen:32,get_nam:[175,179],get_name_by_fid:[31,231],get_notif:[96,99],get_observ:98,get_observable_for_cod:98,get_or_create_librari:[208,210],get_or_create_symbol:214,get_package_logg:[185,186],get_port:47,get_posit:99,get_prunable_vers:218,get_pywin32_postinstall_script:158,get_realtype_info_by_desc:31,get_realtype_info_by_nam:[31,231],get_realtype_info_by_realtype_nam:31,get_realtype_info_list:[31,231],get_realtype_name_list:31,get_single_free_screen:32,get_single_output_nam:35,get_snapshot:[214,220],get_stock:[175,179,228],get_stock_info:232,get_stocks_delist:[175,179,228],get_stub:[20,42],get_symbol:[176,179,214,216],get_text_of_dialog:76,get_today_quotes_by_cod:99,get_trcode_list:35,get_trinfo_by_cod:[35,230,231],get_trinfo_list:[35,231],get_user_config:171,get_valu:99,get_verbos:[185,186],get_vers:[214,216,218],get_version_by_numb:218,get_version_of_symbol:216,getaccountcount:29,getaccountevaluationbalanceasseriesanddatafram:45,getaccountevaluationstatusasseriesanddatafram:[45,231],getaccountexecutionbalanceasseriesanddatafram:45,getaccountlist:[29,231],getaccountrateofreturnasdatafram:45,getactpricelist:17,getapimodulepath:[17,75,230,232],getautologindatpath:29,getbranchcodenam:17,getbrok:99,getcash:96,getchejandata:[17,23],getcodelistbycondit:[45,230,231],getcodelistbyconditionasstream:[45,230,231],getcodelistbymarket:[17,230],getcodelistbymarketaslist:[3,29,230,231],getcommdata:[17,23,45,48,50,232],getcommdataex:17,getcommrealdata:[17,23,45,48,230,231],getconditionfilepath:29,getconditionload:[17,45,48,50],getconditionnamelist:17,getconditionnamelistaslist:[29,230,231],getconnectst:[3,17,230,231],getcurrentstockdataasdatafram:3,getdailyadjustmentratioasdatafram:[3,228],getdailystockdataasdatafram:[3,45,228,230,231],getdata:99,getdatacount:17,getdepositinfo:[45,231],getfirewallstatu:29,getfirstavailableaccount:[29,230,231],getfuturecodebyindex:17,getfuturelist:17,getgeneralcodelist:[3,29],getjsondata:228,getkeyboardsecuritystatu:29,getkosdaqcodelist:[3,29],getkospicodelist:[3,29],getlatesttypelibspec:200,getlogg:230,getlogininfo:17,getmarketpriceinfo:45,getmarkettyp:17,getmastercodenam:[17,230,231],getmasterconstruct:17,getmasterlastpric:17,getmasterlistedstockcnt:[17,29],getmasterlistedstockcntex:[17,29],getmasterlistedstockcntexasint:29,getmasterlistedstockd:17,getmasterstockinfo:[17,29],getmasterstockinfoasdict:29,getmasterstockst:17,getmasterstockstateaslist:29,getminutestockdataasdatafram:[3,45,228],getmonthlist:17,getmonthlystockdataasdatafram:45,getnamelistbymarketaslist:29,getoptionatm:17,getoptioncod:17,getoptioncodebyactpric:17,getoptioncodebymonth:17,getorderlogasdataframe1:45,getorderlogasdataframe2:45,getorderlogasdataframe3:45,getoutputvalu:17,getpcident:232,getposit:96,getrealdataforcodesasstream:[45,230,231],getrepeatcnt:[17,45,48,50,232],getsactpricelist:17,getservergubun:[17,29],getsfobasisassetlist:17,getsfuturecodebyindex:17,getsfuturelist:17,getsmonthlist:17,getsoptionatm:17,getsoptioncod:17,getsoptioncodebyactpric:17,getsoptioncodebymonth:17,getstockbasicinfoasdict:[45,230,231,232],getstockbasicinfoasseri:45,getstockdataasdatafram:3,getstockquot:45,getstockquoteinfoasdatafram:[45,230,231],getstockst:29,getsurveillanceflag:29,getthemegroupcod:17,getthemegrouplist:17,gettickstockdataasdatafram:45,gettypelibspec:200,getupjongcod:[17,29],getupjongcodeaslist:29,getupjongnamebycod:[17,29],getuserid:29,getusernam:29,getvalu:96,getweeklystockdataasdatafram:45,getyearlystockdataasdatafram:45,gfid:35,gidc:31,git:[224,227,231],github:[2,3,4,224,227,231],give:[50,219],given:[50,78,99,151,203,219,224,228],global:232,gmail:0,googl:230,got:230,gpl:231,gplv3:231,grace:47,graphic:227,greater_than:49,greater_than_or_equal_to:49,greatli:224,group:16,group_id:16,group_id_smal:16,group_nam:16,group_tp:16,grpc:[1,15,65,73,114,137,152,172,183,227,230],grpc_client_opt:155,grpc_config:155,grpc_option:[1,152,156,172],grpc_server_and_client_opt:[141,155],grpc_server_opt:155,grt:230,gt:[228,230],guarante:[50,219],gubun:[25,27,53,56,58,88,89,231],guid:227,guidelin:226,h:[152,227,231,232],ha:[18,26,34,81,93,98],han:0,handl:[50,66],handle_by_clicking_button:66,handle_by_emiting_should_restart_sign:66,handle_ev:231,handle_if_need:66,handle_version_upgrade_using_pywinauto:38,handledrequest:49,handler:[11,50,77,132,192],handleversionupgradeusingpywinauto:29,handleversionupgradeusingpywinauto_impl:29,handleversionupgradeusingpywinauto_runscriptinsubprocess:29,has_next:82,has_symbol:[207,209],has_tabl:228,haslivedata:97,have:[78,151,203,224],head:[81,82],header:[16,228],headless:228,help:[151,152,224,227,232],help_option_nam:[150,152],here:[151,224,231],hidden:151,hide:151,hide_input:151,high:[99,228],hint:219,histor:[97,226,229],histori:[224,226,227,228,232],historicalpricerecord:99,hocon:232,home_directori:171,hook:[219,224,231],host:[8,9,42,47,197],how:[151,219,224,228],howev:219,ht:[227,228,230],htm:[3,4],html:228,http:[2,3,4,5,224,227,228,231],hwang:0,i:[23,227,228,230,231],icon:226,id:[29,214,216,218,220,227,230],if_exist:228,iid:200,iloc:228,immut:99,impl:219,implement:[98,132],importerror:168,importlib:[1,160,169,172],inc:227,includ:224,include_delist:[45,118,125,228],include_end:45,include_etf:[3,29],include_etn:[3,29],include_kosdaq:[3,29],include_mutual_fund:[3,29],include_preferred_stock:[3,29],include_reit:[3,29],includeadjustedclos:228,incom:219,increment:151,indent:[125,131,134,151,152,171,218],index:[219,226,228,232],index_col:228,indic:[74,168,219],infer_fid:[45,230,231],infer_fids_by_tr_output:35,info:[228,230,231,232],info_ev:230,inform:[18,26,34,93,227,232],infos_from_data_dir:35,inherit:[19,33,219],initi:[98,99,168,219],initial_today_historical_msg:99,initialize_config_from_expected_path:171,initialize_config_from_given_path:171,initialize_librari:[208,210],initially_included_code_list:231,inlin:[18,26,34,78,93,203,230],inplac:228,input:[17,29,35,45,99,151,152,230,231,232],insecur:[13,50],insid:50,inspect:[18,26,34,93,228],instal:[1,137,152,157,172,224,226,232],install_pywin32:158,instanc:[78,132,203],instanti:50,instead:151,instrument:99,int_column:228,intcompat:22,integ:[151,219],intel:227,intend:132,interact:[147,152,153,232],interfac:[50,132],intern:102,interpret:219,interv:[3,45,124,125,228],intorbool:22,introduct:226,invest:228,invok:50,io:[2,3,4,228,231],ioc:17,ippoeyeslhw:3,ipynb:231,ipython:230,is_32bit:199,is_64bit:199,is_admin:174,is_autologin_en:38,is_chejan_respons:98,is_connect:231,is_currently_in_sess:[181,230],is_delist:[177,179],is_flag:151,is_for_cod:98,is_future_opt:45,is_in_private_network:197,is_inus:32,is_naiv:[180,219],is_readi:42,is_run:47,is_simul:[230,232],is_valid_price_ev:98,is_valid_return_typ:[19,84],is_valid_slot:[33,92],is_window:199,isautologinen:29,isconditionload:[29,45,231],isconnect:[29,231],isfirewallen:29,isflaggedforcaut:29,isimpl:198,isinst:[219,228],iskeyboardsecurityen:29,isliv:97,isn:219,isnaiv:97,isnorm:29,isnotimpl:198,isnotnorm:29,isorderwarningetf:[17,29],isorderwarningetfasboolean:29,isorderwarningstock:[17,29],isorderwarningstockasboolean:29,isort:224,ispyiid:200,ispyiidlik:200,ispyitypelib:200,isrealserv:29,iss_file_encod:157,issfil:157,issimulationserv:29,issu:224,issubclass:98,issuspend:29,isu_cd:228,isu_nm:228,isucd2:228,isucd:228,isunderadministr:29,isundersurveil:29,item:[35,50,99,228],item_id:16,itemcnt:[25,27,53,56,58,88,89],itemnam:232,iter:[11,71,77,80,99,184],itertool:[1,172,183],its:[18,26,34,50,93,151],itself:[18,26,34,93,219],jj:230,job_handl:222,join:232,jsn:206,json:[31,35,219,228,232],json_format:230,json_norm:228,jsonb:219,jsonserializ:[31,35,206],jul:227,jupyt:231,just:[50,224],k:[17,125,131,134],kb:231,keep:224,keep_min:218,kei:[19,33,219,228],kept:219,key_bsecgb:17,key_filenam:113,key_password:113,keyerror:[19,33],keyword:[18,26,34,93],khopenapi:[28,37,231],khopenapictrl:[28,37,231],khtml:228,kika1492:0,kiwoom:[228,231],kiwoom_data:228,kiwoom_data_adjust:228,kiwoom_data_adjusted_clos:228,kiwoom_data_clos:228,kiwoom_entrypoint:228,kiwoom_open_api_plu:[1,15,99,172,230,232],kiwoom_open_api_w:[1,15,172],kiwoomopenapiplusalleventhandl:53,kiwoomopenapiplusallordereventhandl:58,kiwoomopenapiplusbaseordereventhandl:58,kiwoomopenapiplusbidirectionalrealeventhandl:59,kiwoomopenapiplusbooleanreturncodeerror:22,kiwoomopenapiplusbrok:[1,106,172],kiwoomopenapipluscomminfo:96,kiwoomopenapipluscommrqdataratelimit:30,kiwoomopenapipluscondit:[1,15,39,65],kiwoomopenapiplusconditionentri:16,kiwoomopenapiplusconditioneventhandl:[1,61,62,65],kiwoomopenapiplusconditionfil:16,kiwoomopenapiplusdata:[1,106,172],kiwoomopenapiplusdialoghandl:[1,15,65,70],kiwoomopenapiplusdialogtohandl:66,kiwoomopenapiplusdispatchfunct:[1,15,29,32,39,65,232],kiwoomopenapiplusdispatchfunctionsgener:116,kiwoomopenapiplusdispatchsignatur:[1,15,39,65],kiwoomopenapiplusdynamiccal:[1,15,39,65],kiwoomopenapiplusdynamiccallablerunn:19,kiwoomopenapipluseageralleventhandl:53,kiwoomopenapipluseagersomeeventhandl:53,kiwoomopenapiplusentrypoint:[1,15,39,65,228,230,231,232],kiwoomopenapiplusentrypointmixin:[1,15,20,39,65],kiwoomopenapipluserror:[1,15,39,65,99,231],kiwoomopenapipluseventfunct:[1,15,39,65],kiwoomopenapipluseventfunctionsgener:116,kiwoomopenapipluseventhandl:[1,15,27,39,48,52,56,61,62,65],kiwoomopenapipluseventhandlerforgrpc:[1,51,53,54,55,57,58,59,60,61,62,65],kiwoomopenapipluseventhandlerfunct:[1,15,24,39,65],kiwoomopenapipluseventhandlersignatur:[1,15,39,65],kiwoomopenapipluseventstream:[1,106,172],kiwoomopenapiplusjsonerror:99,kiwoomopenapipluskwtreventhandl:[1,61,62,65],kiwoomopenapipluslazyalleventhandl:53,kiwoomopenapipluslazysomeeventhandl:53,kiwoomopenapiplusloadconditioneventhandl:[1,61,62,65],kiwoomopenapiplusloggingeventhandl:[1,15,39,61,62,65,232],kiwoomopenapipluslogineventhandl:[1,61,62,65],kiwoomopenapiplusmanagerappl:[1,15,65,66,70,232],kiwoomopenapiplusmanagerapplicationargumentpars:67,kiwoomopenapiplusnegativereturncodeerror:[22,99],kiwoomopenapiplusordereventchannel:98,kiwoomopenapiplusordereventhandl:[1,61,62,65],kiwoomopenapipluspriceeventchannel:98,kiwoomopenapiplusqaxwidget:[1,15,29,39,65,231,232],kiwoomopenapiplusqaxwidgetmixin:[1,15,28,39,45,65,232],kiwoomopenapiplusqaxwidgetserversidemixin:[28,29],kiwoomopenapiplusqaxwidgetuniversalmixin:[28,29,45],kiwoomopenapiplusratelimit:[1,15,39,65],kiwoomopenapiplusrealeventhandl:[1,61,62,65],kiwoomopenapiplusrealtyp:[1,15,39,65,230,231],kiwoomopenapiplusscreenmanag:[1,15,39,65],kiwoomopenapiplussendconditionratelimit:30,kiwoomopenapiplussendorderratelimit:30,kiwoomopenapiplusserverappl:[1,15,65,70,232],kiwoomopenapiplusserverapplicationargumentpars:68,kiwoomopenapiplusserverapplicationprocess:67,kiwoomopenapiplusserverapplicationsubprocess:67,kiwoomopenapiplusservic:[48,50,230,232],kiwoomopenapiplusservice_pb2:[1,15,62,65],kiwoomopenapiplusservice_pb2_grpc:[1,15,48,62,65],kiwoomopenapiplusservicecli:[1,15,62,65],kiwoomopenapiplusserviceclientsidedynamiccal:[1,15,62,65],kiwoomopenapiplusserviceclientsidesignalconnector:[1,15,62,65],kiwoomopenapiplusserviceclientstub:45,kiwoomopenapiplusserviceclientstubcorewrapp:45,kiwoomopenapiplusserviceclientstubextendedwrapp:45,kiwoomopenapiplusserviceclientstubwrapp:[1,15,62,65,228,230,232],kiwoomopenapiplusservicemessageutil:[1,15,62,65],kiwoomopenapiplusserviceserv:[1,15,62,65],kiwoomopenapiplusserviceservic:[1,15,45,50,62,65,232],kiwoomopenapiplusservicestub:50,kiwoomopenapiplussignalconnector:[1,15,39,65],kiwoomopenapiplussignalhandl:[1,15,65,70],kiwoomopenapiplussignatur:[1,15,18,26,39,65],kiwoomopenapiplussomebidirectionaleventhandl:53,kiwoomopenapiplussomeeventhandl:53,kiwoomopenapiplusstor:[1,106,172],kiwoomopenapiplustimeframeerror:99,kiwoomopenapiplustreventhandl:[1,61,62,65],kiwoomopenapiplustrinfo:[1,15,39,65,230,231],kiwoomopenapiplustypelib:[1,15,39,65],kiwoomopenapiplustypelibspec:[1,15,39,65],kiwoomopenapiplusversionupdat:[1,15,39,65,232],kiwoomopenapiwbooleanreturncodeerror:86,kiwoomopenapiwdispatchsignatur:93,kiwoomopenapiwdynamiccal:[1,15,94,95],kiwoomopenapiwentrypoint:[1,15,94,95],kiwoomopenapiwerror:[1,15,94,95],kiwoomopenapiweventhandl:[1,15,89,94,95],kiwoomopenapiweventhandlerfunct:[1,15,87,94,95],kiwoomopenapiweventhandlersignatur:93,kiwoomopenapiwloggingeventhandl:[1,15,94,95],kiwoomopenapiwnegativereturncodeerror:86,kiwoomopenapiwqaxwidget:[1,15,94,95],kiwoomopenapiwqaxwidgetmixin:[1,15,90,94,95],kiwoomopenapiwsignalconnector:[1,15,94,95],kiwoomopenapiwsignatur:[1,15,94,95],koa_funct:17,koa_normal_buy_kp_ord:230,koapi:[1,224,228,229,232],koastudio:[17,230,231],konex:[17,125,131,134],kosdaq150:231,kospi100:[17,29],kospi200:[17,29],kospi50:[17,29],kr:[157,228],krx100:[17,29],krx:[3,228,231],krx_calendar:230,krx_data:228,krx_data_adjust:228,krx_data_adjusted_clos:228,krx_data_clos:228,krx_download:228,krx_loader:228,krxhistoricaldailypricedata:[1,106,172],krxhistoricaldailypricedatadownload:[1,172,179,183,228],krxhistoricaldailypricedataforbacktestload:[1,172,179,183],krxhistoricaldailypricedatafromsqlit:[1,106,172],krxhistoricaldailypricedataload:[1,172,179,183,228],krxtradingcalendar:[1,106,172],ks:228,kt:[19,33,230],kw:219,kwarg:[18,19,24,26,30,33,34,42,47,78,87,90,92,93,96,97,99,141,147,148,152,159,187,188,189,190,201,203,207,209,219,222,223],l:74,last:224,last_adjust_ratio:228,last_clos:228,latest:225,latest_onli:209,latest_vers:218,lead:226,lee:0,left:228,legend:228,len:[218,230],length:[219,228],less_than:49,less_than_or_equal_to:49,level:[45,50,132,151,172,219,230,232],levelnam:230,lg:[230,231],lib:227,librari:[1,176,177,179,183,208,209,210,211,216,218,221,227],library_delist:[177,179],library_exist:[208,210],library_id:[216,218],licens:[226,227],like:[50,219,224,228],limit:[201,203],line2d:230,line:[50,100,101,151,218,230],lineno:230,linter:224,list:[18,19,26,31,32,34,35,67,68,78,93,150,200,201,203,224],list_convers:[1,15,65,73],list_librari:[208,210],list_shr:228,list_snapshot:209,list_symbol:[207,209],list_to_str:74,list_vers:209,listen:[48,50,230],listenrequest:49,listenrespons:[49,230],liter:219,littl:224,live:50,load:[31,35,50,168,176,177,179,228],load_al:228,load_as_cursor:[176,179],load_dialect_impl:219,load_from_data_dir:35,load_from_databas:[177,179],load_from_datfil:31,load_from_dump_fil:[31,35],load_if_exist:228,load_naiv:228,load_or_download:[177,179,228],loadcondit:[29,45,230],loadconditioncal:[45,48,50],loadconditionrequest:49,loaddispatchsignatur:93,loader:[100,168],loadeventhandlersignatur:93,loadtypelib:200,loc:228,local:[102,180,224,230],local_timezon:219,locality_nam:113,lock:29,log:[1,3,8,20,27,28,29,31,32,33,35,38,45,47,50,51,53,54,56,58,59,60,66,67,68,76,77,80,89,90,92,97,98,99,132,172,183,201,203,230,232],logfil:157,logger:[45,117,118,120,122,124,139,145,152,157,158,166,185,186,222],loggingmeta:185,logic:219,login:[50,152,226,231],login_using_pywinauto:38,logincal:[45,48,50,231],logincredenti:49,loginrequest:49,loginusingpywinauto:29,loginusingpywinauto_impl:29,loginusingpywinauto_runscriptinsubprocess:29,loglevel:[185,186],loglevel_to_verbos:[185,186],long_valu:230,look:224,lookup:50,lookup_nam:[19,33],lookup_typ:45,loop:232,lordkind:17,low:[99,228],lqty:17,lret:23,lt:[228,230],m:[5,224,228,230,231],mai:[168,192,219],main:[9,29,31,35,67,68,131,132,152],maintain:224,major:224,make:[50,151,219,224],make_process_die_when_parent_di:222,manag:[50,224,232],mani:[224,232],map:[18,19,26,29,33,34,93,171],marcap:228,mark:151,market:[3,29,125,131,132,134,228,230,231],market_cod:[131,134],marketcap:[100,101],marketentri:132,master:[3,227],matplotlib:[228,230],max:228,max_work:9,maximum_number_of_screen:32,maxsiz:[80,81],mboard:5,md:232,mdc:228,mdcstat01701:228,mean:[50,228],meet:224,merg:228,messag:[1,4,10,22,25,54,58,60,86,99,132,151,152,154,172,182,183,230,231,232],message_typ:[12,49],messagetodict:230,messeng:[1,172,183,194,196],meta_path:[168,169],metabas:99,metaclass:98,metadata:[13,50,209,211,228,232],metakiwoomopenapiplusbrok:96,metakiwoomopenapiplusdata:97,metakiwoomopenapipluseventstream:98,metakiwoomopenapiplusstor:99,metaparam:99,metapathfind:[168,169],metasingleton:99,metavar:151,method:[11,13,18,26,34,78,93,98,168,203,219],method_nam:[28,45,90],methodrequest:12,methodrespons:12,mic:50,might:[19,33,50,224],min:228,minor:224,minut:[1,123,125,137,232],minute_interv:124,minutes_data:228,misc:[1,172,183,210],miss:[11,13,50],mix:98,mixin:[28,29,45],mkt_nm:228,mktcap:228,mktsel:228,modul:[226,232],module_clsid:[37,93],module_path:[1,15,31,35,65,73,230],modulepath:[1,125,127,137,232],monei:228,money2:5,month:16,more:[19,33,50,224,226,227,228],move:231,mozilla:228,mro:98,msc:227,msec:67,msg:[25,27,53,54,55,56,58,60,88,89,99],msg_err_cond_mismatch:22,msg_err_cond_notfound:22,msg_err_cond_overflow:22,msg_err_connect:[22,86],msg_err_data_rcv_fail:22,msg_err_fail:22,msg_err_firewal:22,msg_err_input:22,msg_err_login:[22,86],msg_err_memori:22,msg_err_mis_1per_exc:22,msg_err_mis_2bill_exc:22,msg_err_mis_300cnt_exc:22,msg_err_mis_3per_exc:22,msg_err_mis_500cnt_exc:22,msg_err_mis_5bill_exc:22,msg_err_no_data:22,msg_err_no_login:86,msg_err_no_regopenapi:86,msg_err_non:[22,86],msg_err_ord_overflow2:22,msg_err_ord_overflow:22,msg_err_ord_symcode_empti:22,msg_err_ord_wrong_accno:86,msg_err_ord_wrong_accpwd:86,msg_err_ord_wrong_acctinfo:22,msg_err_ord_wrong_acctno:22,msg_err_ord_wrong_input:[22,86],msg_err_ord_wrong_qty200:86,msg_err_ord_wrong_qty400:86,msg_err_order_overflow:86,msg_err_other_acc_us:22,msg_err_over_max_data:22,msg_err_over_max_fid:22,msg_err_real_cancel:22,msg_err_rq_string_fail:22,msg_err_rq_struct_fail:22,msg_err_rq_wrong_input:86,msg_err_send_fail:22,msg_err_sise_overflow:[22,86],msg_err_socket_clos:22,msg_err_tr_fail:22,msg_err_trcod:86,msg_err_vers:[22,86],much:50,mult:96,multi:232,multi_data:[230,231],multi_output:[35,230,231],multi_outputs_nam:35,multidata:[49,230],multipl:151,must:219,mycol:219,myepochtyp:219,myjsontyp:219,mypi:224,mytabl:219,mytyp:219,mywindow:231,n:[184,227],naiv:[97,102],name:[8,16,18,19,24,26,31,33,34,35,43,44,45,50,84,87,92,93,96,100,101,125,132,134,151,152,166,181,185,186,214,216,218,224,228,230,231,232],name_list:231,namedtupl:99,namespac:[67,68,150],nan:228,narg:151,narrow:224,nav:231,naver:228,nbsp:[228,230],nbviewer:231,ncodecount:17,ncp:17,ndatalength:23,nerrcod:23,net:231,network:[1,172,183],next:[80,81,82,96],next_clos:230,next_nowait:82,nfid:[17,31],nhn:228,nindex:[17,23],nitemcnt:23,nitemidx:17,nnext:23,no_restart:67,no_verbose_flag_opt:151,non:[4,22,86,99,151,219],none:[3,4,8,9,13,16,17,18,19,20,22,23,24,26,28,29,31,32,33,34,35,40,42,45,47,50,59,66,67,68,69,71,76,77,80,81,82,86,87,92,93,96,97,99,100,101,102,103,104,105,113,150,151,152,154,157,158,166,168,169,171,175,176,177,178,179,185,186,192,194,200,203,206,207,209,218,219,222,228,230,231],nonetyp:34,nor:98,nordertyp:17,noresultfound:218,normal:[151,228],not_equal_to:49,not_executed_onli:[120,125],note:[192,219],notebook:[226,231],notebooks_ipynb:231,notifi:[11,81,96,98],notimpl:[1,172,183],notimplementederror:132,notreadydialog:76,notset:132,now:[224,228,230,231],np:[228,230],nprevnext:17,nprice:17,nqty:17,nrepeatidx:17,nsearch:17,nt:228,ntick:17,ntype:17,ntypeflag:17,num2dat:97,number:[32,151,219,232],number_to_screen_no:32,numpi:[228,230],o:232,object:[13,18,26,34,50,93,99,219],observ:[24,50,81,87,98],occur:[81,98],oco:96,ocx:[17,227,231],off:219,offici:224,offset:35,ohlcv:[228,232],oid:99,ojl:227,ol:231,old_behavior:45,ole_item:93,oleitem:93,on_complet:[81,98],on_ent:[24,51,54,55,57,58,59,60,87],on_error:[81,98],on_event_connect:232,on_event_connect_sign:232,on_exit:[24,59,87],on_next:[81,98],on_ready_runn:19,on_receive_tr_data:[231,232],on_receive_tr_data_sign:[231,232],one:[19,33,50,78,203,224],oneventconnect:[17,23,25,27,45,48,50,53,54,56,57,58,59,60,88,89,232],onli:[18,26,34,50,93,151],onlin:50,onreadydialog:66,onreadyread:77,onreadyrunn:203,onreceivechejan:[17,45,48],onreceivechejandata:[23,25,27,45,48,50,53,56,58,88,89,230,231],onreceiveconditionv:[17,23,25,27,45,48,50,53,55,56],onreceiveinvestrealdata:23,onreceivemsg:[23,25,27,45,48,53,54,56,58,60,88,89,230],onreceiverealcondit:[23,25,27,45,48,50,51,53,56,231],onreceiverealdata:[17,23,25,27,45,48,50,53,56,59,88,89,230,231],onreceivetrcondit:[17,23,25,27,45,48,50,51,53,56,230,231],onreceivetrdata:[17,23,25,27,45,48,50,51,53,54,56,58,60,88,89,230,231,232],onreciev:11,onward:151,op:219,op_err_cond_mismatch:22,op_err_cond_notfound:22,op_err_cond_overflow:22,op_err_connect:[22,23,86],op_err_data_rcv_fail:22,op_err_fail:22,op_err_failur:[22,86],op_err_firewal:22,op_err_input:22,op_err_login:[22,23,86],op_err_memori:22,op_err_mis_1per_exc:22,op_err_mis_2bill_exc:22,op_err_mis_300cnt_exc:22,op_err_mis_3per_exc:22,op_err_mis_500cnt_exc:22,op_err_mis_5bill_exc:22,op_err_no_data:22,op_err_no_login:86,op_err_no_regopenapi:86,op_err_non:[17,22,86],op_err_ord_overflow2:22,op_err_ord_overflow:22,op_err_ord_symcode_empti:22,op_err_ord_wrong_accno:86,op_err_ord_wrong_accpwd:86,op_err_ord_wrong_acctinfo:22,op_err_ord_wrong_acctno:22,op_err_ord_wrong_input:[22,86],op_err_ord_wrong_qty200:86,op_err_ord_wrong_qty400:86,op_err_order_overflow:86,op_err_other_acc_us:22,op_err_over_max_data:22,op_err_over_max_fid:22,op_err_real_cancel:22,op_err_rq_string_fail:[17,22],op_err_rq_struct_fail:[17,22],op_err_rq_wrong_input:86,op_err_send_fail:22,op_err_sise_overflow:[17,22,86],op_err_socket_clos:22,op_err_success:[22,86],op_err_tr_fail:22,op_err_trcod:86,op_err_vers:[22,23,86],open:[99,102,224,228,230,231,232],open_login_window:38,open_login_window_impl:38,openapi:[1,17,45,48,114,137,138,144,147,152,156,172,228,230,232],openapi_meta:[1,125,137,152],oper:[219,224],opt10001:[45,230,232],opt10001_info:231,opt10004:45,opt10007:45,opt10059:231,opt10072:35,opt10073:35,opt10075:[35,45],opt10076:[35,45],opt10079:45,opt10080:45,opt10081:[45,230],opt10081_info:231,opt10082:45,opt10083:45,opt10085:[35,45],opt10087:231,opt10094:45,opt50037:231,opt90005:231,opt_typ:[45,230,231],option:[13,16,19,22,28,29,31,32,33,35,50,66,67,68,76,77,78,132,150,151,171,200,203,224,232],optkwfid:[17,35,45,230],optkwinv:35,optkwpro:35,opw00001:45,opw00004:[17,45],opw00005:[17,45],opw00007:45,opw00018:45,opw20013:231,opw20014:231,opw20015:231,opw20016:231,opw20017:231,order:[1,18,26,34,50,93,96,98,99,119,125,137,152,219,230,232],order_cancel:99,order_cr:99,order_no:[16,45,231],order_typ:[45,152,230,231],ordercal:[45,48,50,230,231],ordereddict:[18,26,34,93],orderlisten:[48,50],orderrequest:49,orders_fil:231,orders_left:231,orderstatu:96,ordersubscriptiontarget:49,ordinari:50,org:224,org_order_no:231,organization_nam:113,orient:219,origin:224,original_order_no:[45,152,230,231],os:[16,31,35,171,232],otc:[17,125,131,134],other:[50,78,151,203,219,232],otherwis:[78,203,219],our:219,out:[219,228,230],output:[122,124,125,135,151,152,228,230,231,232],output_filenam:35,over:50,overal:[18,26,34,93],overflow:17,overrid:[151,219],overridden:219,own:50,owner:96,p:[5,19,33,232],packag:[172,227],page:[1,151,226],pair:102,panda:[181,228,230],pandas_metadata:[218,220],param:[96,97,99,100,101,102,103,104,105,150,159,228],paramet:[17,18,23,26,34,45,78,81,93,98,151,203,219],parameter:[19,33],parent:[19,28,66,67,69,76,77,78,96,203],parenthes:151,parse_arg:[67,68,150],parse_d:228,parse_known_arg:[67,68,150],parser:[1,67,68,149,151,152,172],part:[219,224],partial:[18,26,34,93],particularli:151,pass:[151,219,224,231],password:[151,230],patch:224,path:[75,168,169,171,232],pathlib:[75,171],pathlik:[16,31,35,171],pattern:50,pbr:[230,231,232],pd:[45,228,230,231],pdf:17,per:[230,231,232],percab:96,perform:219,period1:228,period2:228,period:[201,228],pid:[29,38,222],pip:[224,227,231],pipe:[29,71],pipeablemultithreadedrendezv:[1,65,72,73],pipx:[224,231],place:[219,232],placehold:[132,219],platform:[1,172,183,228,232],pleas:224,plimit:96,plot:[228,230],plt:[228,230],plu:[228,231],plugin:232,plusfaq:5,poetri:[224,231],pool:50,pop:32,popen:222,port:[8,9,20,42,47,108,109,110,111,117,118,120,121,122,124,125,131,134,135,136,142,143,152,232],portfolio:16,posit:[18,26,34,93],possibl:[50,125,131,134,224],post:[224,228],post_process:35,postgresql:219,pp:230,pprint:230,pprint_ev:230,pprint_messag:182,pre:[224,231],predefin:50,prefer:219,prefix:[2,8,151,219,227],prepare_issfile_for_instal:157,prepare_issfile_for_uninstal:157,preserving_proto_field_nam:230,pretti:50,prettyprint:230,prev_next:231,prevent:168,previous:50,previous_clos:228,previous_open:230,prevnext:[25,27,29,45,51,53,54,56,58,60,88,89,232],price:[45,96,152,226,229,230,231,232],price_index:232,price_multipli:228,primitivevalu:12,primitivevaluearrai:12,print:[230,231,232],proce:227,process:50,process_bind_param:219,process_result_valu:219,produc:219,product:227,progid:[2,8,28],progress:50,progress_bar:[100,101,176,177,179,228],project:224,prompt:[151,227],prompt_credenti:153,prompt_requir:151,proper:50,properti:[4,11,13,22,24,34,48,52,81,82,86,87,93,175,177,179,185,186,228],propertyrequest:12,propertyrespons:12,propos:224,proto:[11,13,50,147,230,232],protobuf:[13,50,230],protoc:10,protocol:[12,49],provid:219,proxi:[1,7,15,172],prune_previous_vers:209,ptype_accordion:5,pull:[151,226],push:224,put:224,put_notif:99,py:[3,228,230,231,232],pyiid:200,pyiidlik:200,pyitypelib:200,pylint:224,pypi:[224,225,231],pyplot:[228,230],pyqt5:231,pyreadlin:227,pyside2:[1,15,17,19,28,33,65,73,90,160,172,183,186,202,231,232],pystock:231,pytest:224,python:[219,224,226],python_stub:[1,114,115,137],pythoncom3x:227,pythontype_to_qttyp:[34,93],pywin32:[1,137,138,144,152,156,172,183],pywinauto:[1,29,66,76,160,172,230],pywinautofind:[168,169],pywinautoload:168,pywintypes3x:227,q:5,qabstractsocket:187,qabstractsocketlog:[1,77,183,186,191],qabstractsocketloggingmeta:187,qapplic:[231,232],qaxcontain:231,qaxwidget:[19,33,231,232],qcheck:97,qdialoghandl:[1,65,66,73,79],qeventloop:232,qmainwindow:231,qobject:[19,66,76,77,78,188,203],qobjectlog:[1,67,68,183,186,191],qobjectloggingmeta:188,qprocess:67,qpushbutton:231,qratelimitedexecutor:[1,183,202,204],qratelimitedexecutordecoratedfunct:203,qratelimitedexecutorrunn:203,qrunnabl:78,qsignalhandl:[1,65,69,73,79],qstring:[231,232],qt:[17,28,231],qt_qpa_platform_plugin_path:[166,232],qtaxcontain:[1,19,33,160,166,172,232],qtcore:[1,19,28,66,67,76,77,78,160,166,172,188,189,203,232],qtgui:[1,160,166,172,231],qthread:189,qthreadlog:[1,76,183,186,191,203],qthreadloggingmeta:189,qthreadpool:78,qthreadpoolexecutor:[1,65,73,79],qthreadpoolexecutorrunn:78,qtnetwork:[1,160,166,172,187],qtpy:231,qtwidget:[1,28,160,166,172,190,231,232],quantiti:[45,152,230,231],query1:228,queue:[1,15,65,73,98],queuebasedbufferediter:[1,65,73,83],queuebasediterableobserv:[1,65,73,83],queuebasediterableobserveriter:81,queueiter:[1,65,73,80,81,83],quot:[218,222,228,230],quote_typ:[45,152,230,231],qvariant:17,qwidget:[28,190],qwidgetlog:[1,28,90,183,186,191],qwidgetloggingmeta:190,r:[19,33],rais:[132,168,218,228,232],rang:[228,232],rate:98,rate_limit:[1,5,30,172,183],ratelimit:[1,5,30,172,183,202,203],ratelimitedcommrqdata:45,ratelimitedsendcondit:45,raw:132,re:[219,224],read:[207,209],read_as_cursor:[207,209],read_as_datafram:[207,209],read_config:171,read_csv:228,read_sql_tabl:228,readable_nam:[45,230,231],readi:[224,228,230],readm:224,readthedoc:231,ready_runn:19,readydialog:76,readyrunn:203,real:[67,68,232],realcal:[45,48,50,231],realdata:[25,27,53,56,59,88,89],realinfo:[1,125,127,137,232],realrequest:49,realrequestflag:49,realtim:[50,230,232],realtyp:[25,27,53,56,59,88,89,125,129,147,152,231],realtype_by_desc:31,realtype_by_desc_dump_filedir:31,realtype_by_desc_dump_filenam:31,realtype_by_desc_dump_filepath:31,realtype_by_desc_from_datfil:31,realtype_by_desc_from_dump_fil:31,realtype_desc:231,realtype_info:231,realtype_list:231,realtypes_from_datfil:31,reboot:[144,145,157],receiv:[81,98,219,228,230],recent_data:228,reclaim:[78,203],recommend:16,record:[132,151,192,228,230,231],record_nam:231,recorditem:200,recordnam:[25,27,51,53,54,56,58,60,88,89,232],records_from_datafram:99,recurs:[1,172,183],refer:[219,226],refresh_footer_bar:132,refresh_header_bar:132,regist:[50,98,168,169],register_cod:[59,98],reindex:228,reinitialize_serv:47,releas:[225,226],remain:[151,228],rememb:224,remind:224,remov:231,remove_all_cod:59,remove_all_screen:59,remove_cod:59,renam:228,rendezv:71,repeat:230,repeat_cnt:232,repeatedstr:49,repl:231,replac:228,repo:[224,227],repositori:231,repres:[18,26,34,78,93,203],reproduc:224,request:[11,13,48,50,51,53,54,55,57,58,59,60,226,228,230],request_iter:[11,13,48,50,53,59],request_nam:[45,152,230,231],requir:219,reset_index:231,reset_sys_coinit_flag:168,resoliwan:0,resolut:98,resourc:[78,203],respons:[98,228],responseforonreceivechejandata:58,responseforonreceivemsg:58,responseforonreceivetrdata:58,restart:67,restart_and_connect:67,restart_and_restor:67,restart_onli:67,restart_typ:[66,67],restart_with_upd:67,restart_with_update_and_connect:67,restart_with_update_and_restor:67,restarttyp:[66,67],restoreal:77,restoreallhandl:77,restorehandl:77,restorewakeupfiledescrptor:77,result:[19,50,84,203,219,228],ret:[25,27,53,55,56,231],return_annot:[18,26,34,93],return_cod:[67,68],return_screen:32,returnvalu:49,reus:32,revers:[120,125],right:219,roe:[230,231,232],row:[219,228,230,231],rpc:[45,48,50,230,232],rpccontext:230,rpcerror:[230,231],rq_1:17,rqname:[25,27,29,45,51,53,54,56,58,60,88,89,230,232],rst:224,rstrip:231,rule:[16,219],run:[19,76,78,203,224,231],run_as_admin:222,run_fil:222,run_funct:222,run_installer_with_issfil:157,run_script:222,runnabl:[19,203],runscriptinsubprocess_withdata:29,rx:[81,98],s:[50,74,99,151,219,222,224,228,230],saccno:17,safari:228,safe:[78,203,219],same:[18,26,34,93,99,219,231],samsung_cod:230,sarrcod:17,save:228,save_config:171,save_user_config:171,scenario:50,schart:231,schedul:[78,102,203],scode:17,scope:224,screditgb:17,screen:132,screen_len:132,screen_manag:[48,51,54,58,59,60],screen_no:[32,45,152,230,231],screen_no_to_numb:32,screenno:232,script:[152,222],scrnno:[25,27,29,51,53,54,56,58,60,88,89],scrno:[45,232],search:[50,226],search_typ:45,searching_directori:171,searchtext:228,second:151,secugroup:228,secugrp_nm:228,see:219,selecttlb:200,selenium:228,self:[3,4,11,13,17,19,20,22,23,24,25,27,28,29,30,32,33,34,35,38,42,44,45,47,48,50,51,52,53,54,55,56,57,58,59,60,66,67,68,71,76,77,78,80,81,82,84,86,87,88,89,90,92,93,96,97,98,99,100,102,103,105,132,150,151,168,169,175,176,177,178,179,185,186,194,195,201,203,206,207,208,209,210,214,216,218,219,220,228,231],sell:[50,96],sell_onli:[120,125],send:[50,224,230],send_messag:[194,195],sendcondit:[17,45,48,50],sendconditionstop:17,sendord:[17,45,48,50],sendordercredit:17,sendorderfo:17,sens:219,sent:50,sentinel:81,sep:74,sequenc:[16,19,35,67,68,76,81,98,99,150,200],serch:50,seri:45,serial:[1,31,35,172,183,219],serrorcod:23,serv:[1,137,152,172,231,232],server:[13,29,50,228,230],server_and_client_argument_pars:155,server_and_client_bind_address_opt:155,server_and_client_client_cert_file_opt:155,server_and_client_client_key_file_opt:155,server_and_client_client_root_certs_file_opt:155,server_and_client_enable_ssl_opt:155,server_and_client_host_opt:155,server_and_client_no_require_client_auth_opt:155,server_and_client_opt:155,server_and_client_port_opt:155,server_and_client_require_client_auth_opt:155,server_and_client_server_cert_file_opt:155,server_and_client_server_key_file_opt:155,server_and_client_server_root_certs_file_opt:155,server_argument_pars:155,server_bind_address_opt:155,server_cert_file_opt:155,server_key_file_opt:155,server_no_require_client_auth_opt:155,server_opt:155,server_port_opt:155,server_require_client_auth_opt:155,server_root_certs_file_opt:155,servertyp:[67,68],servic:[13,50],session:[1,183,210,221],set:[18,26,34,50,93,151,219,224,227,232],set_footer_bar:132,set_fund_histori:96,set_header_bar:132,set_index:228,set_loglevel:[185,186],set_sys_coinit_flag:168,set_user_config:171,set_verbos:[185,186],setal:77,setconditionsearchflag:[17,29],setdefault:228,setenviron:97,setgeometri:231,sethandl:77,setinfodata:17,setinputvalu:[17,29,45,48,50,231,232],setlevel:230,setloglevel:[45,48,50],setloglevelrequest:49,setloglevelrespons:49,setoutputfid:17,setrealreg:[17,23,45,48,50],setrealremov:[17,45,48,50],setup:224,setwakeupfiledescriptor:77,setwindowtitl:231,sever:[50,78,203],sfidlist:23,sfieldnam:17,sfunctionnam:17,sgubun:23,shape:228,share:[100,101,228],shogagb:17,short_cod:228,should:[151,168,219,224],should_disconnect:231,should_handl:66,should_handle_by_titl:66,shouldrestart:67,show:[1,98,137,151,152,172,228,231,232],show_account_window:38,show_account_window_impl:38,show_default:151,show_entri:132,show_envvar:151,showaccountwindow:[17,29],showcas:226,showmessag:231,shown:151,shutdown:[44,78,203],sid:17,side:[29,50,219],signal:[77,231,232],signatur:[18,26,34,93,219],similar:[50,151,219],simpl:50,simpli:50,simul:[18,26,34,67,68,93,232],sinfodata:17,singl:[151,232],single_data:[230,231,232],single_output:[35,230,231],single_outputs_nam:35,single_to_multi_trcod:35,singledata:[49,230],singleton:223,sinnerfieldnam:17,site:227,size:[96,99],sjongmokcod:17,skip:[224,230],slash:151,sleep_if_necessari:[30,201,203],sloandat:17,slot:[24,33,53,87,92,231],smarket:17,smarketgb:17,smessag:23,smsg:[23,27,56],snapshot:[1,183,209,210,214,217,220,221],snapshot_id:217,snapshotassoci:[1,183,210,221],so:[50,132],softwar:231,sole:50,some:[50,151,224],somecol:219,someth:219,sordtp:17,sorgorderno:17,sorgordno:17,sort:[176,179],sort_index:228,sort_typ:45,sort_valu:228,sourc:[2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,63,66,67,68,69,71,74,75,76,77,78,80,81,82,84,86,87,88,89,90,91,92,93,96,97,98,99,100,101,102,103,104,105,108,109,110,111,112,113,114,115,116,117,118,120,121,122,124,125,126,128,129,130,131,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,157,158,159,166,168,169,171,173,174,175,176,177,178,180,181,182,184,185,186,187,188,189,190,192,194,195,197,198,199,200,201,203,205,206,207,208,209,211,213,214,215,216,217,218,219,220,222,223,226],source_filenam:101,sparam:17,spec:[168,200],special:219,specif:[18,26,34,76,93,132],specifi:[18,26,34,93,99,132,151],sphinx:1,split:[228,230,231],splmmsg:[25,54,58,60,231,232],sprevnext:23,sprice:17,sql:219,sqlalchemi:[1,172,183,210,228],sqlalchemydata:[1,104,106,172],sqlalchemysqlitedata:[1,106,172],sqlite3:228,sqlite:228,sqlitedata:[1,101,106,172],sqlitefilelibrari:[1,172,183,210],sqlitestor:[1,172,183,210],sqlitestorelibrari:[1,172,183,210],srealdata:23,srealkei:23,srealtyp:[17,23],srecordnam:[17,23],srqname:[17,23,27,56],sscnno:17,sscreenno:17,sscrno:[23,27,56],ssl_credenti:[1,112,114,137],sslbytp:17,ssplmmsg:23,stabl:226,stag:17,standard:228,start:[18,26,34,35,47,67,78,93,96,97,99,100,103,105,203,226,230,231,232],start_dat:[3,45,122,124,125,175,177,178,179,228],start_request_iterator_consum:59,start_tim:[176,179,207,209],starting_directori:171,starting_order_no:[45,120,125],stat:228,state:231,state_or_province_nam:113,statement:219,statu:[230,231],status_typ:45,statusbar:231,statusbarhandl:132,statuscod:230,stderr:192,stdin:29,stdout:[29,192],stdscr:132,step:[219,224,227],stock:[50,175,179,226,229,230,231,232],stock_chart_data:231,stock_cod:231,stock_info:231,stock_meta:[1,125,137,152],stock_onli:[120,125],stockchart:3,stockcod:[1,125,133,137,231,232],stockentri:132,stockinfo:[1,125,133,137,231,232],stocklik:96,stockmst2:3,stocknam:[1,125,133,137,232],stocks_delist:[175,179,228],stop:[24,47,76,81,82,87,96,97,99,100,103,105,230],stop_condit:45,stop_listen:230,stop_request_iterator_consum:59,stoplistenrequest:49,stopsid:99,store:[1,18,26,34,93,172,183],str:[16,17,18,19,22,23,26,28,29,31,32,33,34,35,45,50,66,67,68,76,78,132,150,171,203,228,231],stractpric:17,strbaseassetcod:17,strbaseassetgb:17,strcode:[17,23,27,56],strcodelist:[17,23],strconditionindex:23,strconditionnam:[17,23],strdelcod:17,stream:[50,182,192,230,231],streamhandl:192,streaming_ev:99,streaming_pric:99,strfidlist:17,strftime:[228,231],string:[18,26,34,78,93,151,203,230],string_to_list:74,string_valu:[230,231],strip:[219,230,232],stritemnam:17,strmonth:17,strong:[18,26,34,78,93,203],stropttyp:17,strrecordnam:17,strscreenno:17,strscrno:17,strtdd:228,strthemecod:17,strtrcode:17,strtype:23,stub:[43,44,45,98],subclass:[98,132,219],submit:[50,78,96,203],subprocess:[1,29,172,183],subscrib:[81,98],subset:224,succesfulli:228,success:50,sum:228,support:[50,151,224],sure:224,svalu:17,swap_output_typ:35,sy:[168,169,192,227,231,232],symbol:[1,100,101,175,176,177,178,179,183,207,209,210,211,214,216,220,221,228],symbol_id:220,symbols_delist:[177,179],symbols_with_delist:228,sync:50,system:[17,219,224],t000000:230,t00108:17,t00109:17,t090003:230,t0:230,t100015:230,t11814:230,t133453:230,t201:230,t24640:230,t24672:230,t2944654:230,t2:230,t30338:230,t30339:230,t30340:230,t30341:230,t30342:230,t30343:230,t30800:230,t30840:230,t31739:230,t31740:230,t31741:230,t410:230,t411:230,t4596733:230,t4602702:230,t4817707:230,t4817969:230,t4817972:230,t4817973:230,t4817983:230,t4817984:230,t5:230,t608869:230,t608871:230,t608891:230,t608892:230,t61:230,t77221:230,t77222:230,t7884712:230,t7884732:230,t7884994:230,t7884997:230,t7885000:230,t7885001:230,t7885011:230,t7885012:230,t:[98,151,219,224,228,230],tabl:228,table_nam:[218,220],tablenam:[103,105],taehoon1:0,taehoon:0,tag:224,take:132,takesid:99,tarbal:227,target:[13,50,138,139,157,168,169],tax:96,tdd_clsprc:228,tdd_hgprc:228,tdd_lwprc:228,tdd_opnprc:228,temporarili:224,termin:230,test:[50,224,228,230],test_koapi:224,text:[132,151],textio:[16,31,35],thei:224,them:50,thi:[1,18,19,26,33,34,50,67,68,78,93,98,102,132,151,168,192,203,219,224,232],thing:[219,232],those:[50,224],thread:[1,172,183,230,231],thread_pool:[42,78],through:[50,224],ticker:228,time:[1,66,78,99,151,160,169,172,203,219],time_column:[207,209],time_to_timestamp:98,timedelta:[219,228],timefram:99,timeoffset:99,timeout:[13,29,42,47,50,76,80,81,82],timer:[230,231],timestamp:[1,97,181,183,210,211,216,220,221,228,230],timestampcolumn:103,timewindowratelimit:[5,30,201],timezon:102,tip:226,titl:[66,76],tl:231,tlb:200,tmi:228,tmout:99,to_datetim:[228,230],to_dict:[35,206],to_json:206,to_numer:[228,230],to_numpi:228,to_pyside2_event_sign:93,to_pyside2_function_prototyp:[34,93],to_seri:228,to_specif:66,to_sql:228,to_str:132,todat:[100,101],tolist:228,tool:[1,15,39,62,65,224],top:172,tqdm:[1,172,183,186,228],tqdmstreamhandl:[1,183,186,193],tr:[17,23,45,48,230,232],tr_code:[35,231],tr_info:[230,231],tr_info_list:231,tr_name:35,tr_names_svr:35,tr_type:35,traceback:[24,59,87],track:50,tradeid:96,tradingc:102,tradingcalendarbas:102,trai:226,trail:228,trailamount:96,trailperc:96,transact:50,transactioncal:[45,48,50,230,231,232],transactionrequest:49,transactionstopcondit:49,transactionstopconditioncompartor:49,transform:219,transmit:96,travi:224,trcode:[25,27,29,35,45,51,53,54,56,58,60,86,88,89,99,125,130,230,232],trd_dd:228,treat:[102,219],trigger:[50,224],trinfo:[1,125,127,137,147,232],trinfo_by_cod:35,trinfo_by_code_dump_filedir:35,trinfo_by_code_dump_filenam:35,trinfo_by_code_dump_filepath:35,trinfo_by_code_from_data_dir:35,trinfo_by_code_from_dump_fil:35,troubleshoot:224,truncat:228,try_or_rais:[4,22,86],try_or_raise_boolean:[22,86],try_version_update_using_pywinauto:38,tup:99,tupl:[67,68,78,99,150,200,203],tutori:[226,229],two:151,type:[17,18,19,26,33,34,50,81,93,97,98,99,151,185,187,188,189,190,219,226,227,232],type_posit:16,typedecor:219,typeengin:219,typeguard:200,typelib:[36,231],typelib_dll_path:37,typelib_spec:37,typelibspec:200,typeno:228,types_typedecor:219,typic:[19,33,219],tz:[97,102,180,228,230],tz_local:228,ui:232,ultim:219,unari:50,under:224,underli:219,unexpect:[125,131,134,152,218],unicod:219,unind:218,uninstal:[1,137,152,172,227,232],uninstall_pywin32:158,union:[16,22,29,31,32,35,78,171,200,203],unit:228,unknown:[67,68],unless:151,unregist:[50,168,169],unrel:98,until:[78,203],up:[78,98,203,224,232],updat:[1,50,137,152,172,176,177,179,224,226,227],update_version_if_necessari:38,update_wrapper_with_click_param:148,updown:228,upjong:16,upon:219,upper:228,url:[103,194,228],us:[19,33,50,78,98,132,151,192,203,219,224,231],usag:[50,219,226,227],use_posit:96,user:[151,228,232],user_config:171,user_config_filename_cadid:171,user_id:[17,230,232],user_metadata:[218,220],user_nam:17,user_password:[230,232],userid:[17,232],userinfo:[1,119,125,137,232],userpassword:232,usual:[50,151,219],utc:[102,219],utf:[152,171],util:[1,3,5,8,15,20,27,28,29,30,31,32,33,35,38,45,47,50,51,53,54,56,58,59,60,65,66,67,68,69,89,90,92,97,98,99,152,172],v7:228,v:[5,227,232],valid:[96,219],valid_dai:113,valu:[10,50,81,98,99,151,159,200,219,230,231,232],valueerror:[228,232],variabl:[19,33,151,219],variant:219,variou:232,ver:232,verbos:[141,151,152,185,186,232],verbose_flag_opt:151,verbose_opt:[1,147,149,152,156,172],verbose_option_callback:159,verboseopt:151,verbosity_to_loglevel:[185,186],verifi:224,version:[1,16,132,138,140,151,158,183,210,211,216,217,218,221,224,226],version_id:217,version_numb:218,versioneditem:[1,183,210,212],via:[98,219],virtual:98,virtualenv:224,volum:[99,228],volunt:224,vt:[19,33],vtableitem:200,wa:151,wai:[219,224],wait:[29,50,78,203,222],wait_for_don:11,wait_for_readi:[13,50],wait_for_termin:[47,76],waitforfinish:67,waitforstart:67,want:[219,224],warn:[185,219,230,231],warn_on_full_buff:77,warn_on_rpc_error:[182,231],warn_on_rpc_error_context:[182,231],watch:[152,231,232],we:219,web:[224,228],websit:224,welcom:224,well:[18,26,34,93],what:50,whatev:132,when:[50,151,219,224,232],whenev:50,where:219,whether:224,which:[50,132,151,168,192,219],whoever:224,wikidoc:231,win32:227,win32com:200,win64:228,window:[227,228,232],windowflag:28,windowspecif:[66,76],wise:231,with_info:[45,230,231],with_metaclass:96,with_multi:45,within:219,without:[18,26,34,50,78,93,151,203,218,219],won:98,work:[151,219,224],workflow:224,would:[50,224],wrap:[148,201,203],wrap_to_check_code_or_rais:[4,22,86],wrapper:[132,148],write:[192,207,209],x64:228,x86:227,x:231,xkrx:[102,181,228,230],xlsx:[231,232],xml:228,xxxcall:[50,232],y:[227,228,230,231],yahoo:228,yahoo_data:228,yahoo_data_adjusted_clos:228,yahoo_download:228,yahoofinancekrxhistoricaldailypricedatadownload:[1,172,179,183,228],yf:228,yf_data:228,yfinanc:228,yield:231,yml:224,you:[98,224],your:224,your_name_her:224,yunseong:0,yyyymm:17,yyyymmdd:[17,45,231],zero:[151,232],zip:[230,231,232]},titles:["Credits","API Reference","koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypoint","koapy.backend.daishin_cybos_plus.core.CybosPlusEntrypointMixin","koapy.backend.daishin_cybos_plus.core.CybosPlusError","koapy.backend.daishin_cybos_plus.core.CybosPlusRateLimiter","koapy.backend.daishin_cybos_plus.core","koapy.backend.daishin_cybos_plus","koapy.backend.daishin_cybos_plus.proxy.CybosPlusEntrypointProxy","koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService","koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceMessageUtils","koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyServiceServicer","koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2","koapy.backend.daishin_cybos_plus.proxy.CybosPlusProxyService_pb2_grpc","koapy.backend.daishin_cybos_plus.proxy","koapy.backend","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusCondition","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchFunctions","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDispatchSignature","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusDynamicCallable","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypoint","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEntrypointMixin","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusError","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventFunctions","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandler","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerFunctions","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusEventHandlerSignature","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusLoggingEventHandler","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidget","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusQAxWidgetMixin","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRateLimiter","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusRealType","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusScreenManager","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignalConnector","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusSignature","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTrInfo","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLib","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec","koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusVersionUpdater","koapy.backend.kiwoom_open_api_plus.core","koapy.backend.kiwoom_open_api_plus.core.tools.generate_python_stubs","koapy.backend.kiwoom_open_api_plus.core.tools","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClient","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideDynamicCallable","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientSideSignalConnector","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceClientStubWrapper","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceMessageUtils","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServer","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusServiceServicer","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2","koapy.backend.kiwoom_open_api_plus.grpc.KiwoomOpenApiPlusService_pb2_grpc","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusConditionEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlerForGrpc","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusEventHandlers","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusKwTrEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoadConditionEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoggingEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusLoginEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusOrderEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusRealEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event.KiwoomOpenApiPlusTrEventHandler","koapy.backend.kiwoom_open_api_plus.grpc.event","koapy.backend.kiwoom_open_api_plus.grpc","koapy.backend.kiwoom_open_api_plus.grpc.tools.compile_proto","koapy.backend.kiwoom_open_api_plus.grpc.tools","koapy.backend.kiwoom_open_api_plus","koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusDialogHandler","koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusManagerApplication","koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusServerApplication","koapy.backend.kiwoom_open_api_plus.pyside2.KiwoomOpenApiPlusSignalHandler","koapy.backend.kiwoom_open_api_plus.pyside2","koapy.backend.kiwoom_open_api_plus.utils.grpc.PipeableMultiThreadedRendezvous","koapy.backend.kiwoom_open_api_plus.utils.grpc","koapy.backend.kiwoom_open_api_plus.utils","koapy.backend.kiwoom_open_api_plus.utils.list_conversion","koapy.backend.kiwoom_open_api_plus.utils.module_path","koapy.backend.kiwoom_open_api_plus.utils.pyside2.QDialogHandler","koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler","koapy.backend.kiwoom_open_api_plus.utils.pyside2.QThreadPoolExecutor","koapy.backend.kiwoom_open_api_plus.utils.pyside2","koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedBufferedIterator","koapy.backend.kiwoom_open_api_plus.utils.queue.QueueBasedIterableObserver","koapy.backend.kiwoom_open_api_plus.utils.queue.QueueIterator","koapy.backend.kiwoom_open_api_plus.utils.queue","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWDynamicCallable","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEntrypoint","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWError","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandler","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWEventHandlerFunctions","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWLoggingEventHandler","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidget","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWQAxWidgetMixin","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignalConnector","koapy.backend.kiwoom_open_api_w.core.KiwoomOpenApiWSignature","koapy.backend.kiwoom_open_api_w.core","koapy.backend.kiwoom_open_api_w","koapy.backtrader.KiwoomOpenApiPlusBroker","koapy.backtrader.KiwoomOpenApiPlusData","koapy.backtrader.KiwoomOpenApiPlusEventStreamer","koapy.backtrader.KiwoomOpenApiPlusStore","koapy.backtrader.KrxHistoricalDailyPriceData","koapy.backtrader.KrxHistoricalDailyPriceDataFromSQLite","koapy.backtrader.KrxTradingCalendar","koapy.backtrader.SQLAlchemyData","koapy.backtrader.SQLAlchemySQLiteData","koapy.backtrader.SQLiteData","koapy.backtrader","koapy.cli.__main__","koapy.cli.commands.disable.auto_login","koapy.cli.commands.disable","koapy.cli.commands.enable.auto_login","koapy.cli.commands.enable","koapy.cli.commands.generate.grpc","koapy.cli.commands.generate.grpc.ssl_credentials","koapy.cli.commands.generate","koapy.cli.commands.generate.openapi","koapy.cli.commands.generate.openapi.python_stubs","koapy.cli.commands.get.account_data.deposit","koapy.cli.commands.get.account_data.evaluation","koapy.cli.commands.get.account_data","koapy.cli.commands.get.account_data.orders","koapy.cli.commands.get.account_data.userinfo","koapy.cli.commands.get.chart_data.daily","koapy.cli.commands.get.chart_data","koapy.cli.commands.get.chart_data.minute","koapy.cli.commands.get","koapy.cli.commands.get.openapi_meta.errmsg","koapy.cli.commands.get.openapi_meta","koapy.cli.commands.get.openapi_meta.modulepath","koapy.cli.commands.get.openapi_meta.realinfo","koapy.cli.commands.get.openapi_meta.trinfo","koapy.cli.commands.get.stock_meta.codelist","koapy.cli.commands.get.stock_meta.codelist_interactive","koapy.cli.commands.get.stock_meta","koapy.cli.commands.get.stock_meta.stockcode","koapy.cli.commands.get.stock_meta.stockinfo","koapy.cli.commands.get.stock_meta.stockname","koapy.cli.commands","koapy.cli.commands.install","koapy.cli.commands.install.openapi","koapy.cli.commands.install.pywin32","koapy.cli.commands.serve","koapy.cli.commands.show.account_window","koapy.cli.commands.show","koapy.cli.commands.uninstall","koapy.cli.commands.uninstall.openapi","koapy.cli.commands.uninstall.pywin32","koapy.cli.commands.update","koapy.cli.extensions.functools","koapy.cli.extensions","koapy.cli.extensions.parser","koapy.cli.extensions.verbose_option","koapy.cli","koapy.cli.utils.credentials","koapy.cli.utils.fail_with_usage","koapy.cli.utils.grpc_options","koapy.cli.utils","koapy.cli.utils.openapi","koapy.cli.utils.pywin32","koapy.cli.utils.verbose_option","koapy.compat","koapy.compat.pyside2.QtAxContainer","koapy.compat.pyside2.QtCore","koapy.compat.pyside2.QtGui","koapy.compat.pyside2.QtNetwork","koapy.compat.pyside2.QtWidgets","koapy.compat.pyside2","koapy.compat.pywinauto.findwindows","koapy.compat.pywinauto.importlib","koapy.compat.pywinauto","koapy.compat.pywinauto.timings","koapy.config","koapy","koapy.utils.builtin","koapy.utils.ctypes","koapy.utils.data.KrxHistoricalDailyPriceDataDownloader","koapy.utils.data.KrxHistoricalDailyPriceDataForBacktestLoader","koapy.utils.data.KrxHistoricalDailyPriceDataLoader","koapy.utils.data.YahooFinanceKrxHistoricalDailyPriceDataDownloader","koapy.utils.data","koapy.utils.datetime","koapy.utils.exchange_calendars","koapy.utils.grpc","koapy.utils","koapy.utils.itertools","koapy.utils.logging.Logging","koapy.utils.logging","koapy.utils.logging.pyside2.QAbstractSocketLogging","koapy.utils.logging.pyside2.QObjectLogging","koapy.utils.logging.pyside2.QThreadLogging","koapy.utils.logging.pyside2.QWidgetLogging","koapy.utils.logging.pyside2","koapy.utils.logging.tqdm.TqdmStreamHandler","koapy.utils.logging.tqdm","koapy.utils.messaging.DiscordMessenger","koapy.utils.messaging.Messenger","koapy.utils.messaging","koapy.utils.networking","koapy.utils.notimplemented","koapy.utils.platform","koapy.utils.pywin32","koapy.utils.rate_limiting.RateLimiter","koapy.utils.rate_limiting","koapy.utils.rate_limiting.pyside2.QRateLimitedExecutor","koapy.utils.rate_limiting.pyside2","koapy.utils.recursion","koapy.utils.serialization","koapy.utils.store.SQLiteFileLibrary","koapy.utils.store.SQLiteStore","koapy.utils.store.SQLiteStoreLibrary","koapy.utils.store","koapy.utils.store.misc.VersionedItem","koapy.utils.store.misc","koapy.utils.store.sqlalchemy.Base","koapy.utils.store.sqlalchemy.Library","koapy.utils.store.sqlalchemy.Session","koapy.utils.store.sqlalchemy.Snapshot","koapy.utils.store.sqlalchemy.SnapshotAssociation","koapy.utils.store.sqlalchemy.Symbol","koapy.utils.store.sqlalchemy.Timestamp","koapy.utils.store.sqlalchemy.Version","koapy.utils.store.sqlalchemy","koapy.utils.subprocess","koapy.utils.threading","Contributing","History","Welcome to KOAPY\u2019s documentation!","Installation","Getting historical stock price data","Notebooks","KOAPY Tutorial","KOAPY","Usage"],titleterms:{"0":[225,231],"02":225,"07":225,"1":225,"2":231,"2022":225,"7":225,"\uac15\uc81c\ub418\ub294":231,"\uac1c\ub150":231,"\uac1c\ubc1c\uacfc\uc815\uc5d0\uc11c":231,"\uac1d\uccb4":231,"\uac80\uc0c9":231,"\uac83\uc744":231,"\uacc4\uc88c\uc815\ubcf4":231,"\uacfc\uc815\uc5d0\uc11c":231,"\uad00\ub828":231,"\uad00\uc2b5\uc744":231,"\uad6c\uc131":231,"\uad6c\ud604\uc5c6\uc774":231,"\uad6c\ud604\uccb4\ub4e4\uc744":231,"\uae30\ub2a5":231,"\uae30\ub2a5\ub4e4\uc744":231,"\uae30\ubcf8":231,"\uae30\ubcf8\uc815\ubcf4":231,"\ub2e4\uc591\ud55c":231,"\ub2e8\uc21c":231,"\ub2e8\uc77c":231,"\ub300\ud55c":231,"\ub370\ubaa8":231,"\ub370\uc774\ud130":231,"\ub4dc\ub098\ub4e4":231,"\ub77c\uc774\ube0c\ub7ec\ub9ac":231,"\ub85c\uadf8\uc778":231,"\ub85c\ub529":227,"\ub97c":227,"\ub9ac\uc18c\uc2a4":231,"\ub9ac\uc2a4\ud2b8":231,"\ub9e4\ub044\ub7ec\uc6b4":231,"\ub9e4\uc218":231,"\uba40\ud2f0\ub370\uc774\ud130":231,"\uba54\ud0c0":231,"\ubaa9\ub85d":231,"\ubaa9\uc801":231,"\ubaa9\uc801\uc73c\ub85c\uc11c":231,"\ubc0f":231,"\ubc16\uc744":231,"\ubcf5\uc218":231,"\ubcf5\uc7a1\ud558\uc9c0":231,"\ubd80\uc218\uc801\uc73c\ub85c":231,"\ubd88\ub7ec\uc624\uae30":231,"\ubd88\ub7ec\uc628":231,"\ube44\ub3d9\uae30":231,"\ubfd0\ub9cc":231,"\uc0ac\uc6a9":231,"\uc0ac\uc6a9\uc131":231,"\uc0ac\uc6a9\ud574\ubcfc":231,"\uc0ad\uc81c":227,"\uc0bc\uc131\uc804\uc790":231,"\uc0dd\uc131":231,"\uc11c\ubc84":231,"\uc11c\ubc84\uc640\uc758":231,"\uc124\uc815":231,"\uc124\uce58":227,"\uc218":231,"\uc27d\uac8c":231,"\uc2a4\ud2b8\ub9bc":231,"\uc2dc\ub098\ub9ac\uc624\ub4e4\uc5d0":231,"\uc2dc\uc2a4\ud15c":231,"\uc2dc\uc7a5\uac00":231,"\uc2e4\uc2dc\uac04":231,"\uc2f1\uae00\ub370\uc774\ud130":231,"\uc544\ub2c8\ub77c":231,"\uc54a\ub294":231,"\uc54a\uc740":231,"\uc5b4\ud50c\ub9ac\ucf00\uc774\uc158":231,"\uc5b4\ud50c\ub9ac\ucf00\uc774\uc158\ub9cc\uc73c\ub85c":231,"\uc5c5\ub370\uc774\ud2b8":227,"\uc5c6\ub3c4\ub85d":231,"\uc5d4\ud2b8\ub9ac\ud3ec\uc778\ud2b8":231,"\uc5ec\ub7ec":231,"\uc5ec\ub7ec\uac00\uc9c0":231,"\uc5f0\uacb0":231,"\uc624\ub958":227,"\uc694\uccad":231,"\uc6b0\ud68c\ud560":231,"\uc704\ud55c":231,"\uc720\ud2f8\ub9ac\ud2f0":231,"\uc751\ub2f5":231,"\uc758":231,"\uc774\ub984":231,"\uc774\ubca4\ud2b8":231,"\uc774\uc678\uc5d0":231,"\uc778\ud130\ud398\uc774\uc2a4":231,"\uc778\ud574":231,"\uc77c\ubc18\uc801\uc778":231,"\uc784\ud3ec\ud2b8":231,"\uc788\ub3c4\ub85d":231,"\uc790\uc8fc":231,"\uc790\uccb4":231,"\uc804\uc1a1":231,"\uc815\ubcf4":231,"\uc815\ubcf4\ub4e4\uc744":231,"\uc81c\uacf5":231,"\uc81c\ud55c\ub418\uc9c0":231,"\uc870\uac74\uac80\uc0c9":231,"\uc870\uac74\uc2dd":231,"\uc885\ub8cc":231,"\uc885\ubaa9":231,"\uc885\ubaa9\uc758":231,"\uc8fc\ubb38":231,"\uc8fc\uc2dd\uc2dc\uc138":231,"\uc99d\uba85":231,"\ucc28\ud2b8":231,"\ucc98\ub9ac":231,"\ucc98\ub9ac\ub97c":231,"\ucd94\uac00\ub85c":231,"\ucd94\uac00\uc801\uc778":231,"\ucf54\ub4dc":231,"\ucf54\ub4dc\uc640":231,"\ud06c\uac8c":231,"\ud0a4\uc6c0\uc99d\uad8c":231,"\ud0a4\uc6c0\uc99d\uad8c\uc758":231,"\ud14c\uc774\ube14":231,"\ud2b9\uc815":231,"\ud504\ub85c\uadf8\ub798\ubc0d":231,"\ud544\uc694\uac00":231,"\ud544\uc694\ud55c":231,"\ud544\uc694\ud560\ub9cc\ud55c":231,"\ud568\uaed8":231,"\ud568\uc218":231,"\ud574\uacb0\ubc29\ubc95":227,"\ud574\uc81c":231,"\ud574\uce58\uc9c0":231,"\ud638\ucd9c\ub4f1\uc758":231,"\ud638\ud658\uc131\uc73c\ub85c":231,"\ud655\uc778":231,"\ud655\uc778\uc774":231,"\ud658\uacbd\uc774":231,"\ud65c\uc6a9\ud55c":227,"\ud6c4":231,"class":[2,3,5,8,9,11,13,16,17,18,19,20,21,23,24,25,26,27,28,29,30,31,32,33,34,35,38,42,43,44,45,47,48,50,51,52,53,54,55,56,57,58,59,60,66,67,68,69,71,76,77,78,80,81,82,84,87,88,89,90,91,92,93,96,97,98,99,100,101,102,103,104,105,132,150,151,168,169,175,176,177,178,179,185,186,187,188,189,190,192,194,195,201,203,206,207,208,209,210,211,214,216,217,218,219,220,222,223],"function":[9,10,13,31,35,40,46,50,63,74,75,93,108,109,110,111,112,113,114,115,116,117,118,120,121,122,124,125,126,128,129,130,131,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,151,152,153,154,155,157,158,159,166,171,173,174,180,181,182,184,186,197,198,199,200,205,222],"public":231,__main__:107,account_data:[117,118,119,120,121],account_window:142,anaconda:227,apach:231,api:[1,227],attribut:[19,33,34,93,116,117,118,120,122,124,131,132,134,139,145,150,152,155,157,158,159,166,171,181,200,222],auto:232,auto_login:[108,110],backend:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95],backtrad:[96,97,98,99,100,101,102,103,104,105,106],base:213,bug:224,builtin:173,chart_data:[122,123,124],cli:[107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,227,231,232],codelist:131,codelist_interact:132,command:[108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147],compat:[160,161,162,163,164,165,166,167,168,169,170],compile_proto:63,config:171,content:[2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,63,66,67,68,69,71,74,75,76,77,78,80,81,82,84,86,87,88,89,90,91,92,93,96,97,98,99,100,101,102,103,104,105,108,109,110,111,112,113,114,115,116,117,118,120,121,122,124,125,126,128,129,130,131,132,134,135,136,138,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,157,158,159,166,168,169,171,173,174,175,176,177,178,179,180,181,182,184,185,186,187,188,189,190,192,194,195,197,198,199,200,201,203,205,206,207,208,209,210,211,213,214,215,216,217,218,219,220,222,223,226],contribut:224,contributor:0,core:[2,3,4,5,6,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,84,85,86,87,88,89,90,91,92,93,94],credenti:153,credit:[0,231],ctype:174,cybosplusentrypoint:2,cybosplusentrypointmixin:3,cybosplusentrypointproxi:8,cybospluserror:4,cybosplusproxyservic:9,cybosplusproxyservice_pb2:12,cybosplusproxyservice_pb2_grpc:13,cybosplusproxyservicemessageutil:10,cybosplusproxyserviceservic:11,cybosplusratelimit:5,daili:122,daishin_cybos_plu:[2,3,4,5,6,7,8,9,10,11,12,13,14],data:[175,176,177,178,179,228],datetim:180,deploi:224,deposit:117,develop:0,disabl:[108,109],discordmesseng:194,dll:227,document:[224,226],enabl:[110,111],environ:227,errmsg:126,evalu:118,event:[51,52,53,54,55,56,57,58,59,60,61],exampl:232,exchange_calendar:181,extens:[148,149,150,151],fail_with_usag:154,featur:[224,231],feedback:224,findwindow:167,fix:224,from:227,functool:148,gener:[112,113,114,115,116,231],generate_python_stub:40,get:[117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,224,228],gnu:231,grpc:[42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,71,72,112,113,182,231,232],grpc_option:155,gui:231,guidelin:224,histor:228,histori:225,icon:232,implement:224,importlib:168,indic:226,instal:[138,139,140,227,231],introduct:231,itertool:184,kiwoom:227,kiwoom_open_api_plu:[16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83],kiwoom_open_api_w:[84,85,86,87,88,89,90,91,92,93,94,95],kiwoomopenapiplusbrok:96,kiwoomopenapipluscondit:16,kiwoomopenapiplusconditioneventhandl:51,kiwoomopenapiplusdata:97,kiwoomopenapiplusdialoghandl:66,kiwoomopenapiplusdispatchfunct:17,kiwoomopenapiplusdispatchsignatur:18,kiwoomopenapiplusdynamiccal:19,kiwoomopenapiplusentrypoint:20,kiwoomopenapiplusentrypointmixin:21,kiwoomopenapipluserror:22,kiwoomopenapipluseventfunct:23,kiwoomopenapipluseventhandl:[24,53],kiwoomopenapipluseventhandlerforgrpc:52,kiwoomopenapipluseventhandlerfunct:25,kiwoomopenapipluseventhandlersignatur:26,kiwoomopenapipluseventstream:98,kiwoomopenapipluskwtreventhandl:54,kiwoomopenapiplusloadconditioneventhandl:55,kiwoomopenapiplusloggingeventhandl:[27,56],kiwoomopenapipluslogineventhandl:57,kiwoomopenapiplusmanagerappl:67,kiwoomopenapiplusordereventhandl:58,kiwoomopenapiplusqaxwidget:28,kiwoomopenapiplusqaxwidgetmixin:29,kiwoomopenapiplusratelimit:30,kiwoomopenapiplusrealeventhandl:59,kiwoomopenapiplusrealtyp:31,kiwoomopenapiplusscreenmanag:32,kiwoomopenapiplusserverappl:68,kiwoomopenapiplusservice_pb2:49,kiwoomopenapiplusservice_pb2_grpc:50,kiwoomopenapiplusservicecli:42,kiwoomopenapiplusserviceclientsidedynamiccal:43,kiwoomopenapiplusserviceclientsidesignalconnector:44,kiwoomopenapiplusserviceclientstubwrapp:45,kiwoomopenapiplusservicemessageutil:46,kiwoomopenapiplusserviceserv:47,kiwoomopenapiplusserviceservic:48,kiwoomopenapiplussignalconnector:33,kiwoomopenapiplussignalhandl:69,kiwoomopenapiplussignatur:34,kiwoomopenapiplusstor:99,kiwoomopenapiplustreventhandl:60,kiwoomopenapiplustrinfo:35,kiwoomopenapiplustypelib:36,kiwoomopenapiplustypelibspec:37,kiwoomopenapiplusversionupdat:38,kiwoomopenapiwdynamiccal:84,kiwoomopenapiwentrypoint:85,kiwoomopenapiwerror:86,kiwoomopenapiweventhandl:87,kiwoomopenapiweventhandlerfunct:88,kiwoomopenapiwloggingeventhandl:89,kiwoomopenapiwqaxwidget:90,kiwoomopenapiwqaxwidgetmixin:91,kiwoomopenapiwsignalconnector:92,kiwoomopenapiwsignatur:93,koapi:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,226,227,230,231],krxhistoricaldailypricedata:100,krxhistoricaldailypricedatadownload:175,krxhistoricaldailypricedataforbacktestload:176,krxhistoricaldailypricedatafromsqlit:101,krxhistoricaldailypricedataload:177,krxtradingcalendar:102,later:231,lead:0,librari:214,licens:231,list_convers:74,log:[185,186,187,188,189,190,191,192,193],login:232,messag:[194,195,196],messeng:195,minut:124,misc:[211,212],mit:231,modul:[2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,40,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,63,66,67,68,69,71,74,75,76,77,78,80,81,82,84,86,87,88,89,90,91,92,93,96,97,98,99,100,101,102,103,104,105,108,110,113,116,117,118,120,121,122,124,126,128,129,130,131,132,134,135,136,139,140,142,145,146,148,150,151,153,154,155,157,158,159,168,171,173,174,175,176,177,178,180,181,182,184,185,187,188,189,190,192,194,195,197,198,199,200,201,203,205,206,207,208,209,211,213,214,215,216,217,218,219,220,222,223],module_path:75,modulepath:128,more:232,network:197,notebook:229,notimpl:198,open:227,openapi:[115,116,139,145,157,227,231],openapi_meta:[126,127,128,129,130],opt10001:231,opt10081:231,order:120,os:227,packag:[109,111,112,114,115,125,138,141,143,144,147,152,166,169,179,186,210],panda:231,parser:150,pipeablemultithreadedrendezv:71,platform:199,price:228,proxi:[8,9,10,11,12,13,14],pull:224,pyside2:[66,67,68,69,70,76,77,78,79,161,162,163,164,165,166,187,188,189,190,191,203,204],python:[227,231,232],python_stub:116,pywin32:[140,146,158,200,227],pywinauto:[167,168,169,170],qabstractsocketlog:187,qdialoghandl:76,qobjectlog:188,qratelimitedexecutor:203,qsignalhandl:77,qtaxcontain:161,qtcore:162,qtgui:163,qthreadlog:189,qthreadpoolexecutor:78,qtnetwork:164,qtwidget:165,queue:[80,81,82,83],queuebasedbufferediter:80,queuebasediterableobserv:81,queueiter:82,qwidgetlog:190,rate_limit:[201,202,203,204],ratelimit:201,realinfo:129,recurs:205,refer:1,releas:227,report:224,request:224,s:226,serial:206,serv:141,server:232,session:215,show:[142,143],showcas:231,snapshot:216,snapshotassoci:217,sourc:227,sqlalchemi:[213,214,215,216,217,218,219,220,221],sqlalchemydata:103,sqlalchemysqlitedata:104,sqlitedata:105,sqlitefilelibrari:207,sqlitestor:208,sqlitestorelibrari:209,ssl_credenti:113,stabl:227,start:224,stock:228,stock_meta:[131,132,133,134,135,136],stockcod:134,stockinfo:135,stocknam:136,store:[207,208,209,210,211,212,213,214,215,216,217,218,219,220,221],submit:224,submodul:[6,14,39,41,61,62,64,70,72,73,79,83,94,106,109,111,112,115,119,123,127,133,138,143,144,149,156,166,169,172,179,183,186,191,193,196,202,204,210,212,221],subpackag:[7,15,39,62,65,73,95,114,125,137,152,160,172,183,186,202,210],subprocess:222,symbol:218,tabl:226,thread:223,time:170,timestamp:219,tip:224,tool:[40,41,63,64],tqdm:[192,193],tqdmstreamhandl:192,tr:231,trai:232,trinfo:130,tutori:230,type:224,uninstal:[144,145,146],updat:[147,232],usag:[231,232],userinfo:121,util:[71,72,73,74,75,76,77,78,79,80,81,82,83,153,154,155,156,157,158,159,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223],v3:231,verbose_opt:[151,159],version:[220,232],versioneditem:211,welcom:226,write:224,yahoofinancekrxhistoricaldailypricedatadownload:178}}) \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/test_cli.py b/tests/test_cli.py deleted file mode 100644 index a99b8a7f..00000000 --- a/tests/test_cli.py +++ /dev/null @@ -1,19 +0,0 @@ -import re - -from click.testing import CliRunner - -from koapy import cli - - -def test_cli(): - runner = CliRunner() - result = runner.invoke(cli.cli) - assert result.exit_code == 0 - assert "Usage" in result.output - help_result = runner.invoke(cli.cli, ["--help"]) - assert help_result.exit_code == 0 - assert ( - re.search(r"-h, --help[ ]* Show this message and exit.", help_result.output) - is not None - ) - assert "serve" in help_result.output diff --git a/tests/test_koapy.py b/tests/test_koapy.py deleted file mode 100644 index 10fc9953..00000000 --- a/tests/test_koapy.py +++ /dev/null @@ -1,325 +0,0 @@ -import itertools -import re - -import pandas as pd -import pytest - -from pandas.testing import assert_series_equal - -from koapy.backend.kiwoom_open_api_plus.core.KiwoomOpenApiPlusTypeLibSpec import ( - API_MODULE_PATH, -) -from koapy.utils.exchange_calendars import is_currently_in_session -from koapy.utils.platform import is_32bit, is_windows - -# pylint: disable=redefined-outer-name - - -def is_ocx_available(): - if is_windows() and is_32bit(): - return API_MODULE_PATH and API_MODULE_PATH.exists() - return False - - -skipif_ocx_not_available = pytest.mark.skipif( - not is_ocx_available(), - reason="Features using OCX can be tested only in windows 32bit and OpenAPI installed", -) - -skipif_not_currently_in_session = pytest.mark.skipif( - not is_currently_in_session(), - reason="Cannot test this feature while market is not open", -) - - -@pytest.fixture(scope="module") -def entrypoint(): - from koapy import KiwoomOpenApiPlusEntrypoint - - with KiwoomOpenApiPlusEntrypoint() as entrypoint: - entrypoint.EnsureConnected() - assert entrypoint.IsSimulationServer() - yield entrypoint - - -@pytest.fixture(scope="module") -def calendar(): - from exchange_calendars import get_calendar - - calendar = get_calendar("XKRX") - return calendar - - -@pytest.fixture(scope="module") -def downloader(): - from koapy.utils.data import KrxHistoricalDailyPriceDataDownloader - - downloader = KrxHistoricalDailyPriceDataDownloader() - return downloader - - -@skipif_ocx_not_available -def test_GetConnectState(entrypoint): - assert ( - entrypoint.GetConnectState() == 1 - ), "Entrypoint fixture should be in connected state" - - -@skipif_ocx_not_available -def test_GetCodeListByMarket(entrypoint): - code = "005930" - codes = entrypoint.GetCodeListByMarketAsList("0") - assert ( - code in codes - ), "Samsung Electronics not in market, which is unlikely to happen" - - -@skipif_ocx_not_available -def test_GetMasterCodeName(entrypoint): - code = "005930" - name = entrypoint.GetMasterCodeName(code) - assert ( - name == "삼성전자" - ), "Failed to get Samsung Electronics from code, which is unlikely to happen" - - -@skipif_ocx_not_available -def test_KiwoomOpenApiPlusTrInfo(): - from koapy import KiwoomOpenApiPlusTrInfo - - tr_code = "opt10001" - tr_info = KiwoomOpenApiPlusTrInfo.get_trinfo_by_code(tr_code) - tr_info_from_dump = KiwoomOpenApiPlusTrInfo.trinfo_by_code_from_dump_file() - tr_info_from_dump = tr_info_from_dump.get(tr_code) - - assert tr_info == tr_info_from_dump - - -@skipif_ocx_not_available -def test_GetStockBasicInfoAsDict(entrypoint): - code = "005930" - info = entrypoint.GetStockBasicInfoAsDict(code) - name = info["종목명"] - assert ( - name == "삼성전자" - ), "Failed to get Samsung Electronics from code, which is unlikely to happen" - - -@skipif_ocx_not_available -def test_GetDailyStockDataAsDataFrame(entrypoint, calendar, downloader): - code = "005930" - - now = pd.Timestamp.now(calendar.tz).floor("T") - start_date = calendar.previous_close(now).astimezone(calendar.tz).normalize() - end_date = start_date - 5 * calendar.day - - data = entrypoint.GetDailyStockDataAsDataFrame( - code, start_date=start_date, end_date=end_date - ) - data_krx = downloader.download(code, end_date + calendar.day, start_date) - - data_dates = pd.to_datetime(data["일자"], format="%Y%m%d") - data_krx_dates = data_krx.index.to_series() - assert_series_equal( - data_dates, data_krx_dates, check_names=False, check_index=False - ) - - data_closes = pd.to_numeric(data["현재가"]) - data_krx_closes = data_krx["Close"] - assert_series_equal( - data_closes, data_krx_closes, check_names=False, check_index=False - ) - - -@skipif_ocx_not_available -@skipif_not_currently_in_session -def test_GetCodeListByCondition(entrypoint): - entrypoint.EnsureConditionLoaded() - - conditions = entrypoint.GetConditionNameListAsList() - condition_name = "대형 저평가 우량주" - assert condition_name in [item[1] for item in conditions] - - codes, info = entrypoint.GetCodeListByCondition(condition_name, with_info=True) - assert len(codes) > 0 - assert info.shape[0] > 0 - - info_codes = info["종목코드"].tolist() - for code in codes: - assert code in info_codes - - -@skipif_ocx_not_available -@skipif_not_currently_in_session -def test_GetCodeListByConditionAsStream(entrypoint): - entrypoint.EnsureConditionLoaded() - - conditions = entrypoint.GetConditionNameListAsList() - condition_name = "중소형 저평가주" - assert condition_name in [item[1] for item in conditions] - - stream = entrypoint.GetCodeListByConditionAsStream(condition_name, with_info=True) - - condition_event = next(stream) - info_event = next(stream) - - stream.cancel() - - codes = condition_event.arguments[1].string_value.strip(";").split(";") - records = [values.values for values in info_event.multi_data.values] - columns = info_event.multi_data.names - - info = pd.DataFrame.from_records(records, columns=columns) - assert len(codes) > 0 - assert info.shape[0] > 0 - - info_codes = info["종목코드"].tolist() - for code in codes: - assert code in info_codes - - -@skipif_ocx_not_available -@skipif_not_currently_in_session -def test_OrderCall(entrypoint): - first_account_no = entrypoint.GetFirstAvailableAccount() - request_name = "삼성전자 1주 시장가 신규 매수" # 사용자 구분명, 구분가능한 임의의 문자열 - screen_no = "0001" # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당 - account_no = first_account_no # 계좌번호 10자리, 여기서는 계좌번호 목록에서 첫번째로 발견한 계좌번호로 매수처리 - order_type = 1 # 주문유형, 1 : 신규매수 - code = "005930" # 종목코드, 앞의 삼성전자 종목코드 - quantity = 1 # 주문수량, 1주 매수 - price = 0 # 주문가격, 시장가 매수는 가격설정 의미없음 - quote_type = "03" # 거래구분, 03 : 시장가 - original_order_no = "" # 원주문번호, 주문 정정/취소 등에서 사용 - - stream = entrypoint.OrderCall( - request_name, - screen_no, - account_no, - order_type, - code, - quantity, - price, - quote_type, - original_order_no, - ) - - on_receive_msg = next(stream) # 주문완료 - on_receive_tr_data = next(stream) # 주문성공 - on_receive_chejan_data1 = next(stream) # 주문접수 - on_receive_chejan_data2 = next(stream) # 주문체결 - on_receive_chejan_data3 = next(stream) # 주문잔고 - - assert on_receive_msg.name == "OnReceiveMsg" - assert on_receive_msg.arguments[0].string_value == screen_no - assert on_receive_msg.arguments[1].string_value == request_name - - assert on_receive_tr_data.name == "OnReceiveTrData" - assert on_receive_tr_data.single_data.names[0] == "주문번호" - order_no = on_receive_tr_data.single_data.values[0] - assert re.match(r"^\d+$", order_no) - - assert on_receive_chejan_data1.name == "OnReceiveChejanData" - data = dict( - zip( - on_receive_chejan_data1.single_data.names, - on_receive_chejan_data1.single_data.values, - ) - ) - assert data["계좌번호"] == account_no - assert data["주문번호"] == order_no - assert data["종목코드"] == f"A{code}" - assert data["주문상태"] == "접수" - assert data["종목명"] == entrypoint.GetMasterCodeName(code) - assert int(data["주문수량"]) == quantity - assert int(data["주문가격"]) == price - assert int(data["미체결수량"]) == quantity - assert int(data["체결누계금액"]) == 0 - assert data["주문구분"] == "+매수" - assert data["매매구분"] == "시장가" - assert data["화면번호"] == screen_no - - assert on_receive_chejan_data2.name == "OnReceiveChejanData" - data = dict( - zip( - on_receive_chejan_data2.single_data.names, - on_receive_chejan_data2.single_data.values, - ) - ) - assert data["계좌번호"] == account_no - assert data["주문번호"] == order_no - assert data["종목코드"] == f"A{code}" - assert data["주문상태"] == "체결" - assert data["종목명"] == entrypoint.GetMasterCodeName(code) - assert int(data["주문수량"]) == quantity - assert int(data["주문가격"]) == price - assert int(data["미체결수량"]) < quantity - assert int(data["체결누계금액"]) > 0 - assert data["주문구분"] == "+매수" - assert data["매매구분"] == "시장가" - assert data["화면번호"] == screen_no - assert re.match(r"^\d+$", data["체결번호"]) - assert re.match(r"^\d+$", data["체결가"]) - assert re.match(r"^\d+$", data["체결량"]) - - assert on_receive_chejan_data3.name == "OnReceiveChejanData" - data = dict( - zip( - on_receive_chejan_data3.single_data.names, - on_receive_chejan_data3.single_data.values, - ) - ) - assert data["계좌번호"] == account_no - assert data["종목코드"] == f"A{code}" - assert data["종목명"] == entrypoint.GetMasterCodeName(code) - assert int(data["보유수량"]) > 0 - assert int(data["매입단가"]) > 0 - assert int(data["총매입가"]) > 0 - - -@skipif_ocx_not_available -def test_KiwoomOpenApiPlusRealType(): - from koapy import KiwoomOpenApiPlusRealType - - realtype_name = "주식시세" - realtype_info = KiwoomOpenApiPlusRealType.get_realtype_info_by_realtype_name( - realtype_name - ) - realtype_info_from_dump = ( - KiwoomOpenApiPlusRealType.realtype_by_desc_from_dump_file() - ) - realtype_info_from_dump = realtype_info_from_dump.get(realtype_name) - - assert realtype_info == realtype_info_from_dump - - -@skipif_ocx_not_available -@skipif_not_currently_in_session -def test_GetRealDataForCodesAsStream(entrypoint): - from koapy import KiwoomOpenApiPlusRealType - - code = "005930" - realtype_name = "주식시세" - - code_list = [code] - fid_list = KiwoomOpenApiPlusRealType.get_fids_by_realtype_name(realtype_name) - opt_type = "0" # 기존 화면에 추가가 아니라 신규 생성, 1 의 경우 기존 화면번호에 추가 - - stream = entrypoint.GetRealDataForCodesAsStream( - code_list, - fid_list, - opt_type, - screen_no=None, # 화면번호, 0000 을 제외한 4자리 숫자 임의로 지정, None 의 경우 내부적으로 화면번호 자동할당 - infer_fids=True, # True 로 설정 시 주어진 fid_list 를 고집하지 말고 이벤트 처리 함수의 인자로 전달받는 실시간데이터 이름에 따라 유연하게 fid_list 를 추론 - readable_names=True, # True 로 설정 시 각 fid 마다 숫자 대신 읽을 수 있는 이름으로 변환하여 반환 - fast_parse=False, # True 로 설정 시 이벤트 처리 함수내에서 데이터 값 읽기 시 GetCommRealData() 함수 호출 대신, 이벤트 처리 함수의 인자로 넘어오는 데이터를 직접 활용, infer_fids 가 True 로 설정된 경우만 유의미함 - ) - check_count = 10 - events = itertools.islice(stream, check_count) - events = list(events) - stream.cancel() - - for event in events: - assert event.name == "OnReceiveRealData" - assert event.arguments[0].string_value == code - assert event.arguments[1].string_value in ["주식체결"] diff --git a/usage.html b/usage.html new file mode 100644 index 00000000..24540bbd --- /dev/null +++ b/usage.html @@ -0,0 +1,673 @@ + + + + + + + + + Usage — KOAPY 0.8.3 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ +
+

Usage

+
+

Python

+

파이썬 프로젝트에서 KOAPY 를 사용하기 위해서는:

+
import koapy
+
+
+
+
+

CLI

+

커맨드 라인에서 KOAPY 를 사용하기 위해서는:

+
$ koapy
+Usage: koapy [OPTIONS] COMMAND [ARGS]...
+
+Options:
+  --version   Show the version and exit.
+  -h, --help  Show this message and exit.
+
+Commands:
+  disable    Disable many things.
+  enable     Show many things.
+  generate   Generate files.
+  get        Get various types of data.
+  install    Install openapi module and others.
+  login      Ensure logged in when server is up.
+  order      Place an order.
+  serve      Start grpc server with tray application.
+  show       Show many things.
+  uninstall  Uninstall openapi module and others.
+  update     Update openapi module and metadata.
+  watch      Watch realtime data.
+
+
+
+
+

Python (More)

+

KOAPY 를 사용하지 않고 작성한 가장 미니멀한 코드 예시가 다음과 같을 때:

+
import os
+
+import PySide2
+
+QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join(
+    os.path.dirname(PySide2.__file__), "plugins", "platforms"
+)
+os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH
+
+import sys
+
+from PySide2.QtAxContainer import QAxWidget
+from PySide2.QtWidgets import QApplication
+
+app = QApplication(sys.argv)
+control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}")
+
+APIModulePath = control.dynamicCall("GetAPIModulePath()")
+
+print(APIModulePath)
+
+
+

이것을 KOAPY 에서는 아래처럼 제공하고 있습니다:

+
import sys
+
+from koapy import KiwoomOpenApiPlusQAxWidget
+from koapy.compat.pyside2.QtWidgets import QApplication
+
+app = QApplication(sys.argv)
+control = KiwoomOpenApiPlusQAxWidget()
+
+APIModulePath = control.GetAPIModulePath()
+
+print(APIModulePath)
+
+
+

전체적인 구조에서 큰 차이는 없고, 차이점이라면 함수 호출시 dynamicCall 함수를 사용하지 않고 +직접적으로 함수를 호출하고 있다는 점입니다.

+

당장 이렇게 사용할 수도 있겠지만 KOAPY 에서는 이것보다 좀 더 상위의 API 를 제공하고 있기 때문에, +직접 하위 API 를 통해서 컨트롤 할 것이 아니라면 굳이 이렇게 사용할 필요는 없습니다.

+

예시를 좀 더 복잡하게 해서, 로그인 후 특정 종목의 현재가를 가져오는 시나리오를 가정했을때, +만약 이것을 KOAPY 없이 직접 짜는 경우에는 다음처럼 됩니다:

+
import os
+
+import PySide2
+
+QT_QPA_PLATFORM_PLUGIN_PATH = os.path.join(
+    os.path.dirname(PySide2.__file__), "plugins", "platforms"
+)
+os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QT_QPA_PLATFORM_PLUGIN_PATH
+
+import sys
+
+from PySide2.QtAxContainer import QAxWidget
+from PySide2.QtCore import SIGNAL, QEventLoop
+from PySide2.QtWidgets import QApplication
+
+app = QApplication(sys.argv)
+control = QAxWidget("{A1574A0D-6BFA-4BD7-9020-DED88711818D}")
+
+loop = QEventLoop()
+
+
+def comm_connect():
+    err = control.dynamicCall("CommConnect()")
+    if err < 0:
+        raise ValueError(err)
+    loop.exec_()
+
+
+on_event_connect_signal = SIGNAL("OnEventConnect(int)")
+
+
+def on_event_connect(errcode):
+    if errcode < 0:
+        raise ValueError(errcode)
+    if errcode == 0:
+        print("Connected!")
+    control.disconnect(on_event_connect_signal, on_event_connect)
+    loop.exit()
+
+
+control.connect(on_event_connect_signal, on_event_connect)
+
+comm_connect()
+
+
+def get_stock_info(code):
+    rqname = "get_stock_info"
+    trcode = "opt10001"
+    prevnext = 0
+    screenno = "0001"
+    control.dynamicCall("SetInputValue(const QString&, const QString&)", "종목코드", code)
+    err = control.dynamicCall(
+        "CommRqData(const QString&, const QString&, int, const QString&)",
+        rqname,
+        trcode,
+        prevnext,
+        screenno,
+    )
+    if err < 0:
+        raise ValueError(err)
+    loop.exec_()
+
+
+code = "005930"
+price = 0
+
+on_receive_tr_data_signal = SIGNAL(
+    "OnReceiveTrData(const QString&, const QString&, const QString&, const QString&, const QString&, int, const QString&, const QString&, const QString&)"
+)
+
+
+def on_receive_tr_data(
+    scrno, rqname, trcode, recordname, prevnext, datalength, errorcode, message, splmmsg
+):
+    global price
+
+    # single data
+    index = 0
+    itemname = "현재가"
+    price = control.dynamicCall(
+        "GetCommData(const QString&, const QString&, int, const QString&)",
+        trcode,
+        recordname,
+        index,
+        itemname,
+    ).strip()
+
+    # multi data
+    repeat_cnt = control.dynamicCall(
+        "GetRepeatCnt(const QString&, const QString&)", trcode, recordname
+    )
+    if repeat_cnt > 0:
+        prices = []
+        for index in range(repeat_cnt):
+            price_index = control.dynamicCall(
+                "GetCommData(const QString&, const QString&, int, const QString&)",
+                trcode,
+                recordname,
+                index,
+                itemname,
+            ).strip()
+            prices.append(price_index)
+
+    if prevnext not in ["", "0"]:
+        control.dynamicCall(
+            "SetInputValue(const QString&, const QString&)", "종목코드", code
+        )
+        err = control.dynamicCall(
+            "CommRqData(const QString&, const QString&, int, const QString&)",
+            rqname,
+            trcode,
+            int(prevnext),
+            scrno,
+        )
+        if err < 0:
+            raise ValueError(err)
+    else:
+        control.disconnect(on_receive_tr_data_signal, on_receive_tr_data)
+        loop.exit()
+
+
+control.connect(on_receive_tr_data_signal, on_receive_tr_data)
+get_stock_info(code)
+
+print(price)
+
+
+

단순 함수콜에 비해서 추가된 점들을 짚어보면, +이벤트 처리를 위하여 QEventLoop 를 생성하여 이벤트가 들어올 구간에 맞게 exec/exit 를 시키고 있으며, +이벤트를 직접적으로 처리할 콜백 함수들도 알맞게 구현후 적절한 타이밍에 connect/disconnect 하고 있습니다.

+

반면에 KOAPY 를 사용하면 동일한 작업을 아래와 같이 제공된 메서드 (GetStockBasicInfoAsDict) 를 사용해 간단하게 처리가 가능합니다. +좀 더 세부적인 컨트롤이 필요할 경우에는 요청할 TR 에 대한 정보를 직접 설정하고 중간단계의 API (TransactionCall) 를 통해 호출한 뒤에 +반환되는 스트림을 순차적으로 처리하는 식으로 구현이 가능합니다. +앞선 이벤트루프/콜백함수 기반 구현과 비교했을 때 이 방식이 좀 더 직관적입니다.

+
from koapy import KiwoomOpenApiPlusEntrypoint
+
+with KiwoomOpenApiPlusEntrypoint() as context:
+    # 로그인 처리
+    context.EnsureConnected()
+
+    # 이벤트를 알아서 처리하고 결과물만 제공하는 상위 함수 사용 예시
+    code = "005930"
+    info = context.GetStockBasicInfoAsDict(code)
+    print(info)
+    price = info["현재가"]
+    print(price)
+
+    # 이벤트를 스트림으로 반환하는 하위 함수 직접 사용 예시 (위의 상위 함수 내부에서 실제로 처리되는 내용에 해당)
+    rqname = "주식기본정보요청"
+    trcode = "opt10001"
+    screenno = "0001"
+    inputs = {"종목코드": code}
+    output = {}
+
+    # 아래의 함수는 gRPC 서비스의 rpc 함수를 직접 호출함
+    # 따라서 event 메시지의 구조는 koapy/backend/kiwoom_open_api_plus/grpc/KiwoomOpenApiPlusService.proto 파일 참조
+    for event in context.TransactionCall(rqname, trcode, screenno, inputs):
+        names = event.single_data.names
+        values = event.single_data.values
+        for name, value in zip(names, values):
+            output[name] = value
+
+    # 전체 결과 출력 (싱글데이터)
+    print(output)
+
+    # 현재가 값만 출력
+    price = output["현재가"]
+    print(price)
+
+
+

KiwoomOpenApiPlusEntrypoint 객체를 통해 사용 가능한 메서드 목록은 기본적으로 OpenAPI 에서 제공하는 모든 메서드들을 기반으로 합니다. +해당 메서드 목록은 키움 OpenAPI+ 개발 가이드 문서 에서, 혹은 아래 모듈에서 확인 가능합니다.

+

키움 OpenAPI+ 빌트인 함수 목록:

+ +

이후 그런 기본 메서드들을 활용하는 상위 함수들이 구현된 여러 래퍼 클래스들이 단계적으로 적용되면서 +최종적으로 모든 메서드들이 KiwoomOpenApiPlusEntrypoint 객체로 합쳐지는 구조입니다. +따라서 해당 메서드들이 어떤 것들이 있는지 확인하기 위해서는 관련 래퍼 클래스들에 구현된 함수들을 참고하시는 게 좋습니다.

+

주요 래퍼 클래스들을 포함하는 모듈들은 다음과 같습니다:

+ +

여기서의 함수들 중에 XXXCall 패턴의 함수들은 TR/실시간 데이터 처리 등 몇몇 유형화가 가능한 사용 패턴들에 대해서 +미리 구현해놓은 이벤트 처리 로직들이 서버 사이드에서 동작하도록 구성되어 있습니다.

+

혹시나 추후에 이런 메서드들이 다루지 못하는 새로운 사용 패턴이 생기는 경우에 +KiwoomOpenApiPlusService.proto 파일을 수정해 신규 gRPC 메서드를 추가하는 방식으로도 확장이 가능합니다.

+

서버 사이드의 이벤트 처리와 관련해서 참고할만한 모듈들입니다:

+ +
+
+

CLI (More)

+

CLI 는 KOAPY 설치 후 아무 옵션 없이 koapy 명령어만 실행했을 때 출력되는 설명문을 먼저 참고하세요. +이후 필요한 커맨드를 정하고 --help 옵션을 통해 다른 옵션을 어떻게 설정하는지 확인하신 뒤 +최종적으로 옵션을 알맞게 설정해 호출, 사용하는 흐름으로 활용하시면 됩니다.

+
+

Usage example

+

아래는 예시로 맨 처음 커맨드 목록의 커맨드들 중에 get 커맨드를 확인하고 따라가서 +최종적으로 주식기본정보 확인 기능을 사용하는 시나리오입니다.

+
$ koapy
+Usage: koapy [OPTIONS] COMMAND [ARGS]...
+
+Options:
+  --version   Show the version and exit.
+  -h, --help  Show this message and exit.
+
+Commands:
+  configure  Configure many things.
+  get        Get various types of data.
+  install    Install openapi module and others.
+  login      Ensure logged in when server is up.
+  order      Place an order.
+  serve      Start grpc server with tray application.
+  uninstall  Uninstall openapi module and others.
+  update     Update openapi module and metadata.
+  watch      Watch realtime data.
+
+
+
$ koapy get
+Usage: koapy get [OPTIONS] COMMAND [ARGS]...
+
+Options:
+  -h, --help  Show this message and exit.
+
+Commands:
+  codelist    Get stock codes.
+  daily       Get daily OHLCV of stocks.
+  deposit     Get account deposit.
+  errmsg      Get error message for error code.
+  evaluation  Get account evaluation.
+  minute      Get minute OHLCV of stocks.
+  modulepath  Get OpenApi module installation path.
+  orders      Get order history of a date.
+  realinfo    Get real type info.
+  stockcode   Get stock codes.
+  stockinfo   Get basic information of stocks.
+  stockname   Get name for stock codes.
+  trinfo      Get TR info.
+  userinfo    Get user information.
+
+
+
$ koapy get stockinfo
+Usage: koapy get stockinfo [OPTIONS]
+
+Options:
+  -c, --code CODE              Stock code to get.
+  -o, --output FILENAME        Output filename. Optional for single code
+                               (prints to console).
+  -f, --format [md|xlsx|json]  Output format. (default: md)
+  -p, --port PORT              Port number of grpc server (optional).
+  -v, --verbose [0...5]        Set verbosity level.
+  -V, --no-verbose             Force zero verbosity.
+  -h, --help                   Show this message and exit.
+
+
+
$ koapy get stockinfo -c 005930
+|                 | 0        |
+|:----------------|:---------|
+| 종목코드        | 005930   |
+| 종목명          | 삼성전자 |
+| 결산월          | 12       |
+| 액면가          | 100      |
+| 자본금          | 7780     |
+| 상장주식        | 5969783  |
+| 신용비율        | +0.10    |
+| 연중최고        | +62800   |
+| 연중최저        | -42300   |
+| 시가총액        | 3498293  |
+| 시가총액비중    |          |
+| 외인소진률      | 0.00     |
+| 대용가          | 46880    |
+| PER             | 18.51    |
+| EPS             | 3166     |
+| ROE             | 8.7      |
+| PBR             | 1.56     |
+| EV              | 4.52     |
+| BPS             | 37528    |
+| 매출액          | 2304009  |
+| 영업이익        | 277685   |
+| 당기순이익      | 217389   |
+| 250최고         | +62800   |
+| 250최저         | -42300   |
+| 시가            | 0        |
+| 고가            | 0        |
+| 저가            | 0        |
+| 상한가          | +76100   |
+| 하한가          | -41100   |
+| 기준가          | 58600    |
+| 예상체결가      | -0       |
+| 예상체결수량    | 0        |
+| 250최고가일     | 20200120 |
+| 250최고가대비율 | -6.69    |
+| 250최저가일     | 20200319 |
+| 250최저가대비율 | +38.53   |
+| 현재가          | 58600    |
+| 대비기호        | 3        |
+| 전일대비        | 0        |
+| 등락율          | 0.00     |
+| 거래량          | 0        |
+| 거래대비        | 0.00     |
+| 액면가단위      | 원       |
+| 유통주식        | 4450781  |
+| 유통비율        | 74.6     |
+
+
+
+
+

gRPC server

+

CLI 는 명령을 실행할 때마다 매번 프로그램이 새로 실행되는 식이기 때문에 +단순히 명령을 여러 번 연이어 실행하는 경우 (자동 로그인 을 설정해두었더라도) 매번 로그인을 수행해야 하는 번거로움이 있을 수 있습니다.

+

이런 경우 별도 프로세스로 gRPC 서버를 미리 띄워둔 뒤에 다른 창에서 CLI 명령을 실행하게 되면, +최초 로그인 이후의 명령들은 이미 로그인된 서버와 통신하여 명령을 수행하게 되면서 불필요한 로그인 단계를 줄일 수 있습니다.

+
(server) $ koapy serve
+2021-08-20 19:01:37,802 [DEBUG] Creating manager application - KiwoomOpenApiPlusManagerApplication.py:93
+2021-08-20 19:01:45,318 [DEBUG] Creating server application - KiwoomOpenApiPlusServerApplication.py:29
+2021-08-20 19:01:45,401 [DEBUG] Starting server application - KiwoomOpenApiPlusServerApplication.py:147
+2021-08-20 19:01:45,415 [DEBUG] Started server application - KiwoomOpenApiPlusServerApplication.py:149
+2021-08-20 19:01:45,473 [DEBUG] Starting manager application - KiwoomOpenApiPlusManagerApplication.py:303
+2021-08-20 19:01:45,476 [DEBUG] Started manager application - KiwoomOpenApiPlusManagerApplication.py:305
+
+
+
(client) $ koapy login
+Logging in...
+Logged into Simulation server.
+
+
+
(server) $ ...
+2021-08-20 19:01:45,476 [DEBUG] Started manager application - KiwoomOpenApiPlusManagerApplication.py:305
+
+[GetPCIdentity] VER 3.2.0.0  build 2015.8.12
+
+[GetPCIdentity] VER 3.2.0.0  build 2015.8.12
+2021-08-20 19:02:31,012 [DEBUG] OnEventConnect(0) - KiwoomOpenApiPlusLoggingEventHandler.py:89
+2021-08-20 19:02:31,016 [DEBUG] Connected to Simulation server - KiwoomOpenApiPlusManagerApplication.py:406
+
+
+
(client) $ koapy get stockinfo -c 005930
+...
+
+
+
(server) $ ...
+2021-08-20 19:02:31,016 [DEBUG] Connected to Simulation server - KiwoomOpenApiPlusManagerApplication.py:406
+2021-08-20 19:03:04,842 [DEBUG] OnReceiveTrData('8141', '주식기본정보요청', 'opt10001', '', '0') - KiwoomOpenApiPlusLoggingEventHandler.py:22
+
+
+
+
+
+

Tray icon

+

KOAPY 가 동작하는 동안 내부적으로 KiwoomOpenApiPlusManagerApplication 이 구동되며 +이것을 직접 확인할 수 있도록 구동되는 동안 우측하단에 트레이 아이콘을 표시하게끔 구현되어있습니다.

+

이것을 가장 빠르게 확인할 수 있는 방법은 서버를 띄워보는 것입니다.

+
$ koapy serve
+
+
+

총 초록색과 빨간색의 두개의 트레이 아이콘이 우측 하단 트레이에 생기게 됩니다. +그 중 초록색 트레이 아이콘을 우클릭하는 경우 아래와 같은 여러 기능들을 수행할 수 있는 메뉴를 제공합니다.

+
    +
  • 로그인 처리

  • +
  • 자동 로그인 설정

  • +
  • 로그인 여부 확인

  • +
  • 접속중인 서버 타입 확인

  • +
  • 각종 관련 외부링크

  • +
  • 어플리케이션 종료

  • +
+

초록색 트레이 아이콘은 프로그램의 전체적인 관리를 맡으며, 해당 아이콘을 통해 대부분의 상호작용 및 작업처리를 하실 수 있습니다.

+

빨간색 트레이 아이콘의 경우 실제 서버가 동작하는 어플리케이션에 해당하며, 별다른 상호작용 없이 동작 확인을 위한 최소한의 UI 만 제공됩니다. +동작과정에서 서버 프로그램은 관리 프로그램에 의해 관리되며 주기적으로 종종 재시작될 수 있습니다.

+
+
+

Auto login

+

만약에 최초로 사용하시는 경우에는 자동 로그인 설정부터 해놓는 것을 추천드립니다.

+
$ koapy show account-window
+
+
+

위의 명령어 실행시 키움 Open API 로그인 창이 나옵니다.

+

입력창 아래의 고객 아이디 저장 을 체크해서 매번 아이디를 입력하지 않도록 합니다. +그리고 실제 사용이 아닌 테스트 목적이므로 모의투자 접속 을 체크합니다. +참고로 모의투자로 접속하려면 상시 모의투자 를 신청해놓은 상태여야 합니다.

+

이후 고객ID 와 비밀번호를 입력하고 로그인을 진행합니다.

+

만약에 업데이트로 인해 탑재 프로그램을 종료하고 확인 버튼을 누르라는 메시지가 뜨는 경우에 +터미널에서 CTRL+C 로 현재 프로세스를 종료시키거나 아예 터미널을 닫은 뒤 확인 버튼을 누르시면 정상적으로 업데이트가 진행됩니다. +업데이트 과정에서 CLI 프로세스가 종료되었기 때문에 업데이트 완료 후 다시 처음 단계부터 시작해서 로그인을 다시 진행합니다.

+

로그인이 완료되면 이어서 계좌 비밀번호 입력 화면이 나옵니다.

+

여기서 각 계좌의 계좌번호를 입력하고 등록 버튼을 누릅니다. +모의투자의 경우는 모든 계좌의 비밀번호가 0000 이므로 0000 을 입력하고 전체 계좌에 등록 버튼을 누릅니다. +마지막으로 아래의 AUTO 박스를 체크하고 창을 닫습니다.

+

이제 이후부터는 로그인 단계에서 사용자 입력을 묻지 않고 자동으로 로그인이 처리됩니다.

+
+
+

Version update

+

자동 로그인 설정과 관련된 부분이라 이어서 설명합니다.

+

위처럼 자동 로그인을 설정해놓으면 이후에 버전 업데이트가 필요한 경우 업데이트 처리가 제대로 되지 않습니다. +따라서 주기적으로 자동 로그인 설정을 해제하고 수동으로 로그인 진행 후 버전 업데이트를 해주는 작업이 필요합니다.

+

관련해서 퀀트투자를 위한 키움증권 API (파이썬 버전) 책의 버전처리 문서 내용을 참고하시면 대략적인 이해에 도움이 되리라 생각합니다.

+

해당 위키에서는 자동 버전처리에 대한 내용도 설명하고 있는데요. +KOAPY 에서도 실험적으로 자동 버전처리를 수행하는 관련 스크립트들을 아래에 제공하고 있습니다.

+ +

사용방식은 아래와 같습니다.

+

먼저 koapy.conf 이름의 설정 파일을 현재 디렉토리나 홈 폴더 아래에 만들고 아래와 같이 계정 로그인과 관련된 내용들을 상황에 맞게 채워넣습니다.

+
{
+    koapy.backend.kiwoom_open_api_plus.credentials {
+        user_id = "userid"
+        user_password = "userpassword"
+        cert_password = "certpassword"
+        is_simulation = true
+        account_passwords {
+            0000000000 = "0000"
+            1234567890 = "1234"
+        }
+    }
+}
+
+
+

설정파일 전체 예시는 KOAPY 의 기본 설정파일 을 참고하세요. +설정파일의 포맷은 HOCON 포맷입니다.

+

여기서 계좌번호 중 0000000000 은 모든 계좌에 대한 비밀번호로 이해하고 처리합니다. +예를 들어 모의투자의 접속시 위처럼 설정하면 모든 모의계좌에 대한 비밀번호를 “0000” 으로 설정하도록 처리할 수 있습니다.

+

좀 더 쉽게 해당 설정파일을 생성하기 위해서는 첫 로그인 시에 아래 명령을 활용해 로그인하면서 관련 설정을 같이 저장할 수도 있습니다.

+
$ koapy login --interactive
+
+
+

이후 콘솔에서 아래 명령을 주기적으로 실행하는 것으로 OpenAPI 의 버전을 최신으로 유지할 수 있습니다.

+
$ koapy update openapi
+
+
+

스크립트를 통해서 자동으로 사용자 입력을 시뮬레이션하여 처리하는 방식이다 보니 +스크립트가 처리되는 도중에 다른 키보드 혹은 마우스 입력이 발생하는 경우 버전처리가 제대로 되지 않을 수 있다는 점 참고 바랍니다.

+

또한 스크립트를 통해서 자동으로 사용자 입력을 처리하기 위해서는 해당 명령이 관리자 권한으로 실행되어야 하는 점 참고 바랍니다.

+
+
+ + +
+ +
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + \ No newline at end of file