[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# pycharm\n.idea/\n"
  },
  {
    "path": "american_option.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nfrom math import sqrt, exp, inf\nimport numpy as np\n\n\ndef _call_price(s, k, sigma, r, t, steps=100):\n    r_ = exp(r * (t / steps))\n    r_reciprocal = 1.0 / r_\n    u = exp(sigma * sqrt(t / steps))\n    d = 1.0 / u\n    u_square = u ** 2\n    p_u = (r_ - d) / (u - d)\n    p_d = 1.0 - p_u\n    prices = np.zeros(steps + 1)\n    prices[0] = s * d ** steps\n    for i in range(1, steps + 1):\n        prices[i] = prices[i - 1] * u_square\n    values = np.zeros(steps + 1)\n    for i in range(steps + 1):\n        values[i] = max(0.0, prices[i] - k)\n    for j in range(steps, 0, -1):\n        for i in range(j):\n            values[i] = (p_u * values[i + 1] + p_d * values[i]) * r_reciprocal\n            prices[i] = d * prices[i + 1]\n            values[i] = max(values[i], prices[i] - k)\n    # print(values)\n    return values[0]\n\n\ndef _put_price(s, k, sigma, r, t, steps=100):\n    r_ = exp(r * (t / steps))\n    r_reciprocal = 1.0 / r_\n    u = exp(sigma * sqrt(t / steps))\n    d = 1.0 / u\n    u_square = u ** 2\n    p_u = (r_ - d) / (u - d)\n    p_d = 1.0 - p_u\n    prices = np.zeros(steps + 1)\n    prices[0] = s * d ** steps\n    for i in range(1, steps + 1):\n        prices[i] = prices[i - 1] * u_square\n    values = np.zeros(steps + 1)\n    for i in range(steps + 1):\n        values[i] = max(0, k - prices[i])\n    for j in range(steps, 0, -1):\n        for i in range(0, j):\n            values[i] = (p_u * values[i + 1] + p_d * values[i]) * r_reciprocal\n            prices[i] = d * prices[i + 1]\n            values[i] = max(values[i], k - prices[i])\n    return values[0]\n\n\ndef call_price(s, k, sigma, r, t, steps=100):\n    return (_call_price(s, k, sigma, r, t, steps) + _call_price(s, k, sigma, r, t, steps + 1)) / 2.0\n\n\ndef put_price(s, k, sigma, r, t, steps=100):\n    return (_put_price(s, k, sigma, r, t, steps) + _put_price(s, k, sigma, r, t, steps + 1)) / 2.0\n\n\ndef delta(s, k, sigma, r, t, option_type, steps=100):\n    if t == 0.0:\n        if s == k:\n            return {'Call': 0.5, 'Put': -0.5}[option_type]\n        elif s > k:\n            return {'Call': 1.0, 'Put': 0.0}[option_type]\n        else:\n            return {'Call': 0.0, 'Put': -1.0}[option_type]\n    else:\n        price_func = {'Call': call_price, 'Put': put_price}[option_type]\n        return (price_func(s + 0.01, k, sigma, r, t, steps=steps) -\n                price_func(s - 0.01, k, sigma, r, t, steps=steps)) * 50.0\n\n\ndef gamma(s, k, sigma, r, t, option_type, steps=100):\n    if t == 0.0:\n        return inf if s == k else 0.0\n    price_func = {'Call': call_price, 'Put': put_price}[option_type]\n    return (price_func(s + 0.01, k, sigma, r, t, steps=steps) +\n            price_func(s - 0.01, k, sigma, r, t, steps=steps) -\n            price_func(s, k, sigma, r, t, steps=steps) * 2.0) * 10000.0\n\n\ndef theta(s, k, sigma, r, t, option_type, steps=100):\n    price_func = {'Call': call_price, 'Put': put_price}[option_type]\n    t_unit = 1.0 / 365.0\n    if t <= t_unit:\n        return price_func(s, k, sigma, r, 0.0001, steps=steps) - \\\n               price_func(s, k, sigma, r, t, steps=steps)\n    else:\n        return price_func(s, k, sigma, r, t - t_unit, steps=steps) - \\\n               price_func(s, k, sigma, r, t, steps=steps)\n\n\ndef vega(s, k, sigma, r, t, option_type, steps=100):\n    price_func = {'Call': call_price, 'Put': put_price}[option_type]\n    if sigma < 0.02:\n        return 0.0\n    else:\n        return (price_func(s, k, sigma + 0.01, r, t, steps=steps) -\n                price_func(s, k, sigma - 0.01, r, t, steps=steps)) * 50.0\n\n\ndef rho(s, k, sigma, r, t, option_type, steps=100):\n    price_func = {'Call': call_price, 'Put': put_price}[option_type]\n    return (price_func(s, k, sigma, r + 0.001, t, steps=steps) -\n            price_func(s, k, sigma, r - 0.001, t, steps=steps)) * 500.0\n\n\ndef call_iv(c, s, k, t, r=0.03, sigma_min=0.01, sigma_max=3.0, e=0.00001, steps=100):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    call_min = call_price(s, k, sigma_min, r, t, steps)\n    call_max = call_price(s, k, sigma_max, r, t, steps)\n    call_mid = call_price(s, k, sigma_mid, r, t, steps)\n    diff = c - call_mid\n    if c <= call_min:\n        return sigma_min\n    elif c >= call_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > call_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        call_mid = call_price(s, k, sigma_mid, r, t, steps)\n        diff = c - call_mid\n    # print(sigma_mid)\n    return sigma_mid\n\n\ndef put_iv(c, s, k, t, r=0.03, sigma_min=0.01, sigma_max=3.0, e=0.00001, steps=100):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    put_min = put_price(s, k, sigma_min, r, t, steps)\n    put_max = put_price(s, k, sigma_max, r, t, steps)\n    put_mid = put_price(s, k, sigma_mid, r, t, steps)\n    diff = c - put_mid\n    if c <= put_min:\n        return sigma_min\n    elif c >= put_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > put_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        put_mid = put_price(s, k, sigma_mid, r, t, steps)\n        diff = c - put_mid\n    return sigma_mid\n\n\ndef my_test():\n    import matplotlib.pyplot as plt\n    a = np.linspace(1.0 / 365.0, 2, 100)\n    yc, yp = [], []\n    for i in a:\n        yc.append(vega(6.0, 5.0, 0.25, 0.03, i, option_type='Call', steps=100))\n        yp.append(vega(6.0, 5.0, 0.25, 0.03, i, option_type='Put', steps=100))\n    plt.plot(yc)\n    plt.plot(yp)\n    plt.show()\n\n\ndef my_test2():\n    # print(call_price(5.0, 5.0, 0.1, 0.03, 0.4))\n    # call_price(5.0, 5.0, 0.25, 0.03, 0.4, 99)\n    print(call_iv(0.138, 3.046, 3.1, 0.5, r=0.03, sigma_min=0.01, sigma_max=1.0, e=0.00001, steps=100))\n\n\nif __name__ == '__main__':\n    my_test2()\n\n"
  },
  {
    "path": "baw.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nfrom math import log, sqrt, exp, inf\nfrom scipy.stats import norm\nimport scipy.optimize as opt\n\n\ndef bsm_call(s, k, sigma, t, r, q):\n    sqrt_t = sqrt(t)\n    d1 = (log(s / k) + (r - q + sigma ** 2 / 2.0) * t) / (sigma * sqrt_t)\n    d2 = d1 - sigma * sqrt_t\n    return s * exp(-q * t) * norm.cdf(d1) - k * exp(-r * t) * norm.cdf(d2)\n\n\ndef bsm_put(s, k, sigma, t, r, q):\n    sqrt_t = sqrt(t)\n    d1 = (log(s / k) + (r - q + sigma ** 2 / 2.0) * t) / (sigma * sqrt_t)\n    d2 = d1 - sigma * sqrt_t\n    return k * exp(-r * t) * norm.cdf(-d2) - s * exp(-q * t) * norm.cdf(-d1)\n\n\ndef find_sx(sx, k, sigma, t, r, q, option_type):\n    n = 2.0 * (r - q) / sigma ** 2\n    k_ = 2.0 * r / sigma ** 2 / (1.0 - exp(-r * t))\n    if sx < 0.0:\n        return inf\n    if option_type == 'Call':\n        q2 = (1.0 - n + sqrt((n - 1.0) ** 2 + 4.0 * k_)) / 2.0\n        return (bsm_call(sx, k, sigma, t, r, q) + (1.0 - exp(-q * t)\n                * norm.cdf((log(sx / k) + (r - q + sigma ** 2 / 2.0)) / (sigma * sqrt(t))))\n                * sx / q2 - sx + k) ** 2\n    else:\n        q1 = (1.0 - n - sqrt((n - 1.0) ** 2 + 4.0 * k_)) / 2.0\n        return (bsm_put(sx, k, sigma, t, r, q) - (1.0 - exp(-q * t)\n                * norm.cdf(-(log(sx / k) + (r - q + sigma ** 2 / 2.0)) / (sigma * sqrt(t))))\n                * sx / q1 + sx - k) ** 2\n\n\ndef baw_call(s, k, sigma, t, r, q=0.0):\n    c = bsm_call(s, k, sigma, t, r, q)\n    sx = opt.fmin(lambda i: find_sx(i, k, sigma, t, r, q, 'Call'), s)[0]\n    d1 = (log(sx / k) + (r - q + sigma ** 2 / 2.0)) / (sigma * sqrt(t))\n    n = 2.0 * (r - q) / sigma ** 2.0\n    k_ = 2.0 * r / (sigma ** 2 * (1.0 - exp(-r * t)))\n    q2 = (1.0 - n + sqrt((n - 1.0) ** 2 + 4.0 * k_)) / 2.0\n    a2 = sx * (1.0 - exp(-q * t) * norm.cdf(d1)) / q2\n    return c + a2 * (s / sx) ** q2 if s < sx else s - k\n\n\ndef baw_put(s, k, sigma, t, r, q=0.0):\n    p = bsm_put(s, k, sigma, t, r, q)\n    sx = opt.fmin(lambda i: find_sx(i, k, sigma, t, r, q, 'Put'), s)[0]\n    d1 = (log(sx / k) + (r - q + sigma ** 2 / 2.0)) / (sigma * sqrt(t))\n    n = 2.0 * (r - q) / sigma ** 2\n    k_ = 2.0 * r / (sigma ** 2 * (1.0 - exp(-r * t)))\n    q1 = (1.0 - n - sqrt((n - 1.0) ** 2 + 4.0 * k_)) / 2.0\n    a1 = -sx * (1.0 - exp(-q * t) * norm.cdf(-d1)) / q1\n    return p + a1 * (s / sx) ** q1 if s > sx else k - s\n\n\ndef call_iv(c, s, k, t, r=0.03, sigma_min=0.0001, sigma_max=3.0, e=0.00001):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    call_min = bsm_call(s, k, sigma_min, t, r, 0.0)\n    call_max = bsm_call(s, k, sigma_max, t, r, 0.0)\n    call_mid = bsm_call(s, k, sigma_mid, t, r, 0.0)\n    diff = c - call_mid\n    if c <= call_min:\n        return sigma_min\n    elif c >= call_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > call_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        call_mid = bsm_call(s, k, sigma_mid, t, r, 0.0)\n        diff = c - call_mid\n    return sigma_mid\n\n\ndef put_iv(c, s, k, t, r=0.03, sigma_min=0.0001, sigma_max=3.0, e=0.00001):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    put_min = bsm_put(s, k, sigma_min, t, r, 0.0)\n    put_max = bsm_put(s, k, sigma_max, t, r, 0.0)\n    put_mid = bsm_put(s, k, sigma_mid, t, r, 0.0)\n    diff = c - put_mid\n    if c <= put_min:\n        return sigma_min\n    elif c >= put_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > put_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        put_mid = bsm_put(s, k, sigma_mid, t, r, 0.0)\n        diff = c - put_mid\n    return sigma_mid\n\n\ndef delta(s, k, sigma, t, r, option_type):\n    if t == 0.0:\n        if s == k:\n            return 0.5 if option_type == 'Call' else -0.5\n        elif s > k:\n            return 1.0 if option_type == 'Call' else 0.0\n        else:\n            return 0.0 if option_type == 'Call' else -1.0\n    else:\n        price_func = baw_call if option_type == 'Call' else baw_put\n        return (price_func(s + 0.01, k, sigma, t, r) -\n                price_func(s - 0.01, k, sigma, t, r)) * 50.0\n\n\ndef gamma(s, k, sigma, t, r, option_type):\n    if t == 0.0:\n        return inf if s == k else 0.0\n    price_func = baw_call if option_type == 'Call' else baw_put\n    return (price_func(s + 0.01, k, sigma, t, r) +\n            price_func(s - 0.01, k, sigma, t, r) -\n            price_func(s, k, sigma, t, r) * 2.0) * 10000.0\n\n\ndef theta(s, k, sigma, t, r, option_type):\n    price_func = baw_call if option_type == 'Call' else baw_put\n    t_unit = 1.0 / 365.0\n    if t <= t_unit:\n        return price_func(s, k, sigma, 0.0001, r) - \\\n               price_func(s, k, sigma, t, r)\n    else:\n        return price_func(s, k, sigma, t - t_unit, r) - \\\n               price_func(s, k, sigma, t, r)\n\n\ndef vega(s, k, sigma, t, r, option_type):\n    price_func = baw_call if option_type == 'Call' else baw_put\n    if sigma < 0.02:\n        return 0.0\n    else:\n        return (price_func(s, k, sigma + 0.01, t, r) -\n                price_func(s, k, sigma - 0.01, t, r)) * 50.0\n\n\ndef rho(s, k, sigma, t, r, option_type):\n    price_func = baw_call if option_type == 'Call' else baw_put\n    return (price_func(s, k, sigma, t, r + 0.001,) -\n            price_func(s, k, sigma, t, r - 0.001,)) * 500.0\n\n\nif __name__ == '__main__':\n    # print(baw_call(2707, 2900, 0.165, 78.0 / 365, 0.03, 0.0))\n    # print(baw_put(2710, 2750, 0.15, 78.0 / 365, 0.03, 0.0))\n    print(call_iv(24.0, 2710, 2900, 78.0 / 365))\n    print(put_iv(92.5, 2710, 2750, 78.0 / 365))\n\n"
  },
  {
    "path": "european_option.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nfrom math import log, sqrt, exp\nimport numpy as np\nfrom scipy.stats import norm\n\n\n# def bs_call(s, k, sigma, r, t):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     d2 = d1 - sigma * np.sqrt(t)\n#     return s * norm.cdf(d1) - k * np.exp(-r * t) * norm.cdf(d2)\n#\n#\n# def bs_put(s, k, sigma, r, t):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     d2 = d1 - sigma * np.sqrt(t)\n#     return k * np.exp(-r * t) * norm.cdf(-d2) - s * norm.cdf(-d1)\n\ndef greeks(s, k, sigma, r, t, option_type):\n    sqrt_t = sqrt(t)\n    d1 = (log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * sqrt_t)\n    d2 = d1 - sigma * sqrt_t\n    tmp = exp(-pow(d1, 2) / 2.0)\n    tmp2 = sqrt(2.0 * np.pi * t)\n    tmp3 = r * k * exp(-r * t)\n    gamma = tmp / (s * sigma * tmp2)\n    theta_call = -(s * sigma * tmp) / (2.0 * tmp2) - tmp3 * norm.cdf(d2)\n    vega = s * sqrt_t * tmp / sqrt(2.0 * np.pi)\n    if option_type == 'Call':\n        delta = norm.cdf(d1)\n        theta = theta_call\n    else:\n        delta = norm.cdf(d1) - 1.0\n        theta = theta_call + tmp3\n    return delta, gamma, theta, vega\n\n#\n# def delta(s, k, sigma, r, t, option_type):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     if option_type == 'Call':\n#         return norm.cdf(d1)\n#     else:\n#         return norm.cdf(d1) - 1.0\n#\n#\n# def gamma(s, k, sigma, r, t):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     return np.exp(-pow(d1, 2) / 2.0) / (s * sigma * np.sqrt(2.0 * np.pi * t))\n#\n#\n# def theta(s, k, sigma, r, t, option_type):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     d2 = d1 - sigma * np.sqrt(t)\n#     theta_call = -(s * sigma * np.exp(-pow(d1, 2) / 2.0)) / (2.0 * np.sqrt(2.0 * np.pi * t)) - \\\n#         r * k * np.exp(-r * t) * norm.cdf(d2)\n#     if option_type == 'Call':\n#         return theta_call\n#     else:\n#         return theta_call + r * k * np.exp(-r * t)\n#\n#\n# def vega(s, k, sigma, r, t):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     return s * np.sqrt(t) * np.exp(-pow(d1, 2) / 2.0) / np.sqrt(2.0 * np.pi)\n#\n#\n# def rho(s, k, sigma, r, t, option_type):\n#     d1 = (np.log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * np.sqrt(t))\n#     d2 = d1 - sigma * np.sqrt(t)\n#     if option_type == 'Call':\n#         return k * t * np.exp(-r * t) * norm.cdf(d2)\n#     else:\n#         return -k * t * np.exp(-r * t) * norm.cdf(-d2)\n\n\ndef bs_call(s, k, sigma, r, t):\n    tmp = sqrt(t)\n    d1 = (log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * tmp)\n    d2 = d1 - sigma * tmp\n    return s * norm.cdf(d1) - k * exp(-r * t) * norm.cdf(d2)\n\n\ndef bs_put(s, k, sigma, r, t):\n    tmp = sqrt(t)\n    d1 = (log(s / k) + (r + pow(sigma, 2) / 2.0) * t) / (sigma * tmp)\n    d2 = d1 - sigma * tmp\n    return k * exp(-r * t) * norm.cdf(-d2) - s * norm.cdf(-d1)\n\n\ndef call_iv(c, s, k, t, r=0.03, sigma_min=0.01, sigma_max=1.0, e=0.00001):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    call_min = bs_call(s, k, sigma_min, r, t)\n    call_max = bs_call(s, k, sigma_max, r, t)\n    call_mid = bs_call(s, k, sigma_mid, r, t)\n    diff = c - call_mid\n    if c <= call_min:\n        return sigma_min\n    elif c >= call_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > call_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        call_mid = bs_call(s, k, sigma_mid, r, t)\n        diff = c - call_mid\n    # print(sigma_mid)\n    return sigma_mid\n\n\ndef put_iv(c, s, k, t, r=0.03, sigma_min=0.01, sigma_max=1.0, e=0.00001):\n    sigma_mid = (sigma_min + sigma_max) / 2.0\n    put_min = bs_put(s, k, sigma_min, r, t)\n    put_max = bs_put(s, k, sigma_max, r, t)\n    put_mid = bs_put(s, k, sigma_mid, r, t)\n    diff = c - put_mid\n    if c <= put_min:\n        return sigma_min\n    elif c >= put_max:\n        return sigma_max\n    while abs(diff) > e:\n        if c > put_mid:\n            sigma_min = sigma_mid\n        else:\n            sigma_max = sigma_mid\n        sigma_mid = (sigma_min + sigma_max) / 2.0\n        put_mid = bs_put(s, k, sigma_mid, r, t)\n        diff = c - put_mid\n    return sigma_mid\n\n\n# def my_test():\n#     call_iv(0.138, 3.046, 3.1, 0.5, r=0.03, sigma_min=0.01, sigma_max=1.0, e=0.000001)\n#\n#\n# def my_test2():\n#     import matplotlib.pyplot as plt\n#     a = np.linspace(0, 0.8, 100)\n#     yc, yp = [], []\n#     for i in a:\n#         yc.append(vega(6.0, 5.0, i, 0.03, 0.5))\n#         yp.append(vega(6.0, 5.0, i, 0.03, 0.5))\n#     plt.plot(yc)\n#     plt.plot(yp)\n#     plt.show()\n\n\n# if __name__ == '__main__':\n#     my_test2()\n\n"
  },
  {
    "path": "historical_implied_volatility.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport math\nimport datetime\nfrom io import BytesIO\nfrom copy import deepcopy\n\nimport matplotlib.pyplot as plt\n\nfrom sina_stock_kline_api import get_stock_day_kline\nfrom sina_future_kline_api import get_future_day_kline\nfrom sina_commodity_option_api import get_option_kline as get_future_option_day_kline\nfrom sina_etf_option_api import get_option_day_kline as get_etf_option_day_kline\nimport european_option\n# import american_option\nimport baw\n\n\nETF_SPOT_CODE = {\n    '510050': 'sh510050',\n    '510300': 'sh510300',\n    '159919': 'sz159919',\n}\n\nSTOCK_SPOT_CODE = deepcopy(ETF_SPOT_CODE)\nSTOCK_SPOT_CODE.update({\n    '000300': 'sh000300',\n})\n\n\ndef days_interval(date1, date2):\n    d1 = datetime.datetime.strptime(str(date1), \"%Y%m%d\")\n    d2 = datetime.datetime.strptime(str(date2), \"%Y%m%d\")\n    days = abs((d1 - d2).days)\n    return days, float(days) / 365.0\n\n\ndef get_kline(option_code, spot_code):\n    if spot_code in ETF_SPOT_CODE:\n        option_kline = get_etf_option_day_kline(option_code)\n    else:\n        option_kline = get_future_option_day_kline(option_code)\n    if spot_code in STOCK_SPOT_CODE:\n        spot_kline = get_stock_day_kline(STOCK_SPOT_CODE[spot_code])\n    else:\n        spot_kline = get_future_day_kline(spot_code)\n    return option_kline, spot_kline\n\n\ndef align_kline(option_kline, spot_kline):\n    if not option_kline or not spot_kline:\n        return [], []\n    else:\n        if 'c' in option_kline[0]:\n            date_key, close_key, date_func = 'd', 'c', lambda x: int(''.join(x.split('-')))\n        else:\n            date_key, close_key, date_func = 'date', 'close', lambda x: int(''.join(x[:10].split('-')))\n        option_data = [(date_func(i[date_key]), float(i[close_key])) for i in option_kline]\n        if 'c' in spot_kline[0]:\n            date_key, close_key, date_func = 'd', 'c', lambda x: int(''.join(x.split('-')))\n        else:\n            date_key, close_key, date_func = 'date', 'close', lambda x: int(''.join(x[:10].split('-')))\n        spot_data, option_data2 = [], []\n        len_option_data = len(option_data)\n        index = 0\n        for k in spot_kline:\n            k_date = date_func(k[date_key])\n            op_date = option_data[index][0]\n            while k_date > op_date:\n                # print(f'Warning, miss option kline date: {k_date}', option_data[index])\n                index += 1\n                op_date = option_data[index][0]\n            if k_date == op_date:\n                spot_data.append((k_date, float(k[close_key])))\n                option_data2.append(option_data[index])\n                index += 1\n            if index >= len_option_data:\n                break\n        # print(option_data)\n        # print(spot_data)\n        return option_data2, spot_data\n\n\ndef cal_historical_iv(option_kline, spot_kline, strike_price, expiry_date, r, option_type, exercise_type):\n    if exercise_type == 'european':\n        iv_func = european_option.call_iv if option_type == 'Call' else european_option.put_iv\n    else:\n        iv_func = baw.call_iv if option_type == 'Call' else baw.put_iv\n    x, y, option_cp, spot_cp = [], [], [], []\n    for option, spot in zip(option_kline, spot_kline):\n        x.append(str(option[0]))\n        t = days_interval(option[0], expiry_date)[1]\n        y.append(iv_func(option[1], spot[1], strike_price, t, r=r))\n        option_cp.append(option[1])\n        spot_cp.append(spot[1])\n    return x, y, option_cp, spot_cp\n\n\ndef draw_picture(option_code, x, iv, option_cp, spot_cp, show=True):\n    interval = math.ceil(len(x) / 20)\n    real_x = list(range(len(x)))\n    x_index = real_x[::-interval]\n    x_label = x[::-interval]\n    fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0}, figsize=(12.0, 5.7))\n    axs[0].plot(iv, color='r')\n    axs[0].set_xlim((real_x[0], real_x[-1]))\n    axs[0].set_ylabel('Implied Volatility')\n    axs[0].set_title(option_code)\n    axs[0].grid()\n    line1 = axs[1].plot(option_cp, 'blue', label='option')\n    ax2 = axs[1].twinx()\n    line2 = ax2.plot(spot_cp, 'orange', label='spot')\n    axs[1].set_xticks(x_index[::-1])\n    axs[1].set_xticklabels(x_label[::-1], rotation=60)\n    axs[1].set_ylabel('Price')\n    axs[1].grid()\n    lines = line1 + line2\n    line_labels = [i.get_label() for i in lines]\n    axs[1].legend(lines, line_labels, loc=0)\n    plt.tight_layout()\n    if show:\n        plt.show()\n    else:\n        buffer = BytesIO()\n        plt.savefig(buffer, format='png')\n        return buffer.getvalue()\n\n\ndef main(option_code, spot_code, strike_price, expiry_date, option_type, exercise_type):\n    option_kline, spot_kline = get_kline(option_code, spot_code)\n    op_k, sp_k = align_kline(option_kline, spot_kline)\n    x, iv, option_cp, spot_cp = cal_historical_iv(op_k, sp_k, strike_price, expiry_date, 0.03, option_type, exercise_type)\n    draw_picture(option_code, x, iv, option_cp, spot_cp)\n\n\nif __name__ == '__main__':\n    # main('cu2003C51000', 'cu2003', 51000.0, '20200224', 'Call', 'european')\n    # main('au2004P340', 'au2004', 340.0, '20200325', 'Put', 'european')\n    # main('io2002C4050', '000300', 4050.0, '20200221', 'Call', 'european')\n    # main('10002194', '510050', 3.1, '20200226', 'Call', 'european')\n    # main('m2005C2800', 'm2005', 2800.0, '20200408', 'Call', 'american')\n    main('m2005P2600', 'm2005', 2600.0, '20200408', 'Put', 'american')\n    # main('ta2005P4800', 'ta2005', 4800.0, '20200403', 'Put', 'american')\n"
  },
  {
    "path": "historical_volatility.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport math\nfrom io import BytesIO\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sina_stock_kline_api import get_stock_day_kline, get_ex_data\nfrom sina_future_kline_api import get_future_day_kline\n\n\nETF_SPOT_MAP = {\n    'sh510050': 'sh000016',\n    'sh510300': 'sh000300',\n    'sz159919': 'sh000300',\n}\n\n\ndef cal_stock_fluctuation(code, kline, ex):\n    x, y = [], []\n    kline_data = kline[code]\n    for index, i in enumerate(kline_data):\n        if index > 0:\n            y.append(math.log(i['close'] / kline_data[index - 1]['close']))\n            x.append(int(''.join(i['date'][:10].split('-'))))\n    if code in ETF_SPOT_MAP:\n        listed_date = int(''.join(kline_data[0]['date'][:10].split('-')))\n        ex_date = [int(''.join(i['djr'][:10].split('-'))) for i in ex[code] if i['djr']]\n        ex_date = [i for i in ex_date if i > listed_date][::-1]\n        ex_result = {}\n        if ex_date:\n            spot_kline = kline[ETF_SPOT_MAP[code]]\n            last_date, last_close = 0, 0.0\n            for index, i in enumerate(spot_kline):\n                this_date = int(''.join(i['date'][:10].split('-')))\n                if index > 0:\n                    if last_date <= ex_date[0] < this_date:\n                        ex_result[this_date] = math.log(i['close'] / last_close)\n                        ex_date = ex_date[1:]\n                        if not ex_date:\n                            break\n                last_date = this_date\n                last_close = i['close']\n        # print(ex_result)\n        for index, i in enumerate(x):\n            if i in ex_result:\n                # print(i, y[index], ex_result[i])\n                y[index] = ex_result[i]\n    return x, y\n\n\ndef get_stock_data(code):\n    kline = {code: get_stock_day_kline(code)}\n    if code in ETF_SPOT_MAP:\n        kline[ETF_SPOT_MAP[code]] = get_stock_day_kline(ETF_SPOT_MAP[code])\n        ex = {code: get_ex_data(code)}\n    else:\n        ex = {code: []}\n    return cal_stock_fluctuation(code, kline, ex)\n\n\ndef cal_future_fluctuation(kline):\n    x, y = [], []\n    if kline:\n        last_close = float(kline[0]['c'])\n        for k in kline[1:]:\n            x.append(int(''.join(k['d'].split('-'))))\n            close = float(k['c'])\n            y.append(math.log(close / last_close))\n            last_close = close\n    return x, y\n\n\ndef get_future_data(code):\n    return cal_future_fluctuation(get_future_day_kline(code))\n\n\ndef cal_historical_volatility(y, window_size):\n    y2 = y[::-1]\n    hv_lines, hv_cone = [], []\n    factor = np.sqrt(252) * 100.0\n    for w in window_size:\n        hv = [np.std(y2[i: i + w]) * factor for i in range(len(y2) - w + 1)]\n        hv_lines.append(hv)\n        # hv_cone.append((max(hv), np.percentile(hv, 75), np.median(hv), np.percentile(hv, 25), min(hv), hv[0]))\n    return hv_lines, hv_cone\n\n\ndef draw_picture(code, x, y, interval, window_size, show=True):\n    hv_lines, hv_cone = cal_historical_volatility(y, window_size)\n    x_int = list(range(len(x)))\n    len_window = len(window_size)\n    fig, axs = plt.subplots(2, len_window, sharey=True, gridspec_kw={'hspace': 0, 'wspace': 0}, figsize=(13, 6.4))\n    ylim = None\n    for i in range(len_window):\n        axs[0, i].hist(hv_lines[i], orientation='horizontal', bins=30, alpha=0.6, color='Orange')\n        axs[0, i].axhline(hv_lines[i][0], color='r')\n        axs[0, i].set_title(str(window_size[i]))\n        if ylim is None:\n            ylim = axs[0, i].get_ylim()\n        else:\n            axs[0, i].set_ylim(ylim)\n        axs[0, i].get_xaxis().set_visible(False)\n        axs[1, i].axis('off')\n    axs[0, 0].set_ylabel('historical volatility(%)')\n    axs2 = fig.subplots(2, 1, gridspec_kw={'hspace': 0, 'wspace': 0})\n    axs2[0].axis('off')\n    for hv in hv_lines:\n        x_hv = x_int[-len(hv):]\n        axs2[1].plot(x_hv, hv[::-1])\n    x_hv = x_int[-len(hv_lines[0]):]\n    axs2[1].set_xlim((min(x_hv), max(x_hv)))\n    axs2[1].legend([str(i) for i in window_size])\n    xticks = x[-len(hv_lines[0]):][::-interval][::-1]\n    xticks_index = x_hv[::-interval][::-1]\n    axs2[1].set_xticks(xticks_index)\n    axs2[1].set_xticklabels([str(i) for i in xticks], rotation=60)\n    axs2[1].set_ylabel('historical volatility(%)')\n    axs2[1].set_xlabel(f'historical volatility of {code} in different window size')\n    plt.tight_layout()\n    if show:\n        plt.show()\n    else:\n        buffer = BytesIO()\n        plt.savefig(buffer, format='png')\n        return buffer.getvalue()\n\n\ndef main(code, security_type='stock', window_size=(5, 15, 30, 50, 70, 90, 120, 150)):\n    # import pickle, os\n    # if os.path.isfile('cache'):\n    #     with open('cache', 'rb') as fp:\n    #         x = pickle.load(fp)\n    #         y = pickle.load(fp)\n    #         hv_lines = pickle.load(fp)\n    #         hv_cone = pickle.load(fp)\n    # else:\n    #     x, y = get_stock_data(code)\n    #     hv_lines, hv_cone = cal_historical_volatility(y, window_size)\n    #     with open('cache', 'wb') as fp:\n    #         pickle.dump(x, fp)\n    #         pickle.dump(y, fp)\n    #         pickle.dump(hv_lines, fp)\n    #         pickle.dump(hv_cone, fp)\n    if security_type == 'stock':\n        x, y = get_stock_data(code)\n    elif security_type == 'future':\n        x, y = get_future_data(code)\n    else:\n        return\n    interval = math.ceil(len(x) / 20)\n    draw_picture(code, x, y, interval, window_size, show=True)\n\n\nif __name__ == '__main__':\n    # main('sz159919')\n    # main('sh000300')\n    main('m2005', security_type='future', window_size=(5, 15, 30, 50, 90, 120))\n\n"
  },
  {
    "path": "readme.md",
    "content": "## ETF期权隐含波动率曲面和希腊字母\n用新浪财经的ETF期权数据(目前支持50ETF期权和上交所300ETF期权)\n画出的隐含波动率曲面和希腊字母，能随着行情变化更新。\n\n![图1](https://github.com/sfl666/50ETF_option/blob/master/iv.png)\n\n## 标的历史波动率\n支持ETF期权、指数期权和商品期权。\n\n![图2](https://github.com/sfl666/50ETF_option/blob/master/hv.png)\n\n## 期权历史的隐含波动率\n不支持深交所300ETF期权和部分不活跃的商品期权。\n\n![图3](https://github.com/sfl666/50ETF_option/blob/master/hiv.png)\n\n## 期权最近交易日1分钟线级别的隐含波动率\n只支持上交所期权。\n\n![图4](https://github.com/sfl666/50ETF_option/blob/master/min1_iv.png)\n"
  },
  {
    "path": "sina_commodity_option_api.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport json\nimport requests\n\n\nhttp_header = {\n    'User-Agent': \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) \"\n                  \"Chrome/97.0.4692.71 Safari/537.36\",\n    'Referer': \"https://stock.finance.sina.com.cn/\",\n}\n\n\nPIN_ZHONG_PARAMS = {\n    'io': {'product': 'io', 'exchange': 'cffex'},\n    'm': {'product': 'm_o', 'exchange': 'dce'},\n    'c': {'product': 'c_o', 'exchange': 'dce'},\n    'i': {'product': 'i_o', 'exchange': 'dce'},\n    'cf': {'product': 'cf', 'exchange': 'czce'},\n    'sr': {'product': 'sr', 'exchange': 'czce'},\n    'ta': {'product': 'ta', 'exchange': 'czce'},\n    'ma': {'product': 'ma', 'exchange': 'czce'},\n    'ru': {'product': 'ru_o', 'exchange': 'shfe'},\n    'cu': {'product': 'cu_o', 'exchange': 'shfe'},\n    'au': {'product': 'au_o', 'exchange': 'shfe'},\n    'rm': {'product': 'rm', 'exchange': 'czce'},\n}\nURL_T_QUOTATION = \"http://stock.finance.sina.com.cn/futures/api/openapi.php/OptionService.getOptionData?\" \\\n                  \"type=futures&product={product}&exchange={exchange}&pinzhong={code}\"\nURL_KLINE = \"https://stock.finance.sina.com.cn/futures/api/jsonp.php//\" \\\n            \"FutureOptionAllService.getOptionDayline?symbol={code}\"\nURL_PRICE = \"https://hq.sinajs.cn/etag.php?list=P_OP_{code}\"\nURL_UNDERLYING_PRICE = \"http://hq.sinajs.cn/list={code}\"\nURL_UNDERLYING_PRICE2 = \"http://hq.sinajs.cn/list=nf_{code}\"\nURL_000300 = \"http://hq.sinajs.cn/list=sh000300\"\n\n\ndef get_t_quotation(code):\n    \"\"\"获取T型报价数据\"\"\"\n    p = ''.join(filter(str.isalpha, code))\n    data = requests.get(URL_T_QUOTATION.format(code=code, **PIN_ZHONG_PARAMS[p])).json()['result']['data']\n    up = data['up'] if 'up' in data else []\n    down = data['down'] if 'down' in data else []\n    for i in down:\n        s = []\n        for j in i[-1][::-1]:\n            if j.isdigit():\n                s.append(j)\n            else:\n                break\n        strike_price = ''.join(s[::-1])\n        i.insert(-1, strike_price)\n    return up, down\n\n\ndef get_option_kline(code):\n    \"\"\"获取日K线数据\"\"\"\n    return json.loads(requests.get(URL_KLINE.format(code=code)).content.split(b'(')[1].split(b')')[0])\n\n\ndef get_option_price(code):\n    \"\"\"获取实时行情数据\"\"\"\n    data = requests.get(URL_PRICE.format(code=code), headers=http_header).content.split(b'\"')[1].decode().split(',')\n    return data\n\n\ndef get_underlying_price(code):\n    \"\"\"获取标的(期货)实时行情\"\"\"\n    return requests.get(URL_UNDERLYING_PRICE.format(code=code), headers=http_header).content.split(b'\"')[1].decode('gbk').split(',')\n\n\ndef get_underlying_price2(code):\n    \"\"\"获取标的(期货)实时行情\"\"\"\n    return requests.get(URL_UNDERLYING_PRICE2.format(code=code), headers=http_header).content.split(b'\"')[1].decode('gbk').split(',')\n\n\ndef get_000300_price():\n    \"\"\"获取指数000300实时行情\"\"\"\n    return requests.get(URL_000300, headers=http_header).content.split(b'\"')[1].decode('gbk').split(',')\n\n\ndef my_test():\n    header = ['买量', '买价', '最新价', '卖价', '卖量', '持仓量', '涨跌(%)', '行权价', '代码']\n    up, down = get_t_quotation('io2002')\n    for i in up + down:\n        print(list(zip(header, i)))\n    day_kline = get_option_kline('m2005C2400')\n    print()\n    for i in day_kline:\n        print('日期:{d}, 开:{o}, 高:{h}, 低:{l}, 收:{c}, 成交:{v}'.format(**i))\n    header2 = ['买量', '买价', '最新价', '卖价', '卖量', '持仓量', '涨幅', '行权价', '昨收价', '开盘价', '涨停价',\n               '跌停价', '申卖价五', '申卖量五', '申卖价四', '申卖量四', '申卖价三', '申卖量三', '申卖价二',\n               '申卖量二', '申卖价一', '申卖量一', '申买价一', '申买量一', '申买价二', '申买量二', '申买价三',\n               '申买量三', '申买价四', '申买量四', '申买价五', '申买量五', '行情时间', '主力合约标识', '状态码',\n               '标的证券类型', '标的股票', '期权合约简称', '振幅', '最高价', '最低价', '成交量', '成交额']\n    price_data = get_option_price('io2002C4000')\n    print()\n    for i in zip(header2, price_data):\n        print(i)\n    header3 = ['期货名称', '现在交易时间', '开盘价', '最高价', '最低价', '(昨?)收盘价', '竞买价', '竞卖价', '最新价',\n               '动态结算价', '昨日结算价', '买量', '卖量', '持仓量', '成交量', '交易所', '品种', '日期', '是否热门',\n               '5天最高', '5天最低', '10天最高', '10天最低', '20天最高', '20天最低', '55天最高', '55天最低', '加权平均']\n    future_data = get_underlying_price('M2005')\n    print()\n    for i in zip(header3, future_data):\n        print(i)\n    header4 = ['股票名字', '今日开盘价', '昨日收盘价', '当前价格', '今日最高价', '今日最低价', '竞买价', '竞卖价',\n               '成交的股票数', '成交金额', '买一量', '买一价', '买二量', '买二价', '买三量', '买三价', '买四量', '买四价',\n               '买五量', '买五价', '卖一量', '卖一价', '卖二量', '卖二价', '卖三量', '卖三价', '卖四量', '卖四价',\n               '卖五量', '卖五价', '日期', '时间']\n    price_000300 = get_000300_price()\n    print()\n    for i in zip(header4, price_000300):\n        print(i)\n\n\nif __name__ == '__main__':\n    my_test()\n    # print(get_option_price('m2005C2400'))\n\n"
  },
  {
    "path": "sina_commodity_option_spider.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport requests\n\n\nURL = \"https://stock.finance.sina.com.cn/futures/view/optionsDP.php/{product}/{exchange}\"\n\n\ndef get_instruments(product, exchange):\n    data = requests.get(URL.format(product=product, exchange=exchange)).content\n    data1 = data[data.find(b'option_suffix'):]\n    data2 = data1[:data1.find(b'</ul>')].split(b'</li>')\n    instruments = sorted(set(i[i.rfind(b'>') + 1:].decode().lower() for i in data2[:-1]), key=lambda x: int(x[-4:]))\n    return instruments\n\n\nif __name__ == '__main__':\n    print(get_instruments('ma', 'czce'))\n\n"
  },
  {
    "path": "sina_etf_option_api.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nfrom json import loads\nfrom requests import get\n\nhttp_header = {\n    'User-Agent': \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) \"\n                  \"Chrome/97.0.4692.71 Safari/537.36\",\n    'Referer': \"https://stock.finance.sina.com.cn/\",\n}\n\n\ndef get_option_dates(cate='50ETF', exchange='null'):\n    url = f\"http://stock.finance.sina.com.cn/futures/api/openapi.php/StockOptionService.getStockName?\" \\\n          f\"exchange={exchange}&cate={cate}\"\n    dates = get(url).json()['result']['data']['contractMonth']\n    return [''.join(i.split('-')) for i in dates][1:]\n\n\ndef get_option_expire_day(date, cate='50ETF', exchange='null'):\n    url = \"http://stock.finance.sina.com.cn/futures/api/openapi.php/StockOptionService.getRemainderDay?\" \\\n          \"exchange={exchange}&cate={cate}&date={year}-{month}\"\n    url2 = url.format(year=date[:4], month=date[4:], cate=cate, exchange=exchange)\n    data = get(url2).json()['result']['data']\n    if int(data['remainderDays']) < 0:\n        url2 = url.format(year=date[:4], month=date[4:], cate='XD' + cate, exchange=exchange)\n        data = get(url2).json()['result']['data']\n    return data['expireDay'], int(data['remainderDays'])\n\n\ndef get_option_codes(date, underlying='510050'):\n    url_up = ''.join([\"http://hq.sinajs.cn/list=OP_UP_\", underlying, str(date)[-4:]])\n    url_down = ''.join([\"http://hq.sinajs.cn/list=OP_DOWN_\", underlying, str(date)[-4:]])\n    data_up = str(get(url_up, headers=http_header).content).replace('\"', ',').split(',')\n    codes_up = [i[7:] for i in data_up if i.startswith('CON_OP_')]\n    data_down = str(get(url_down, headers=http_header).content).replace('\"', ',').split(',')\n    codes_down = [i[7:] for i in data_down if i.startswith('CON_OP_')]\n    return codes_up, codes_down\n\n\ndef get_option_price(code):\n    url = \"http://hq.sinajs.cn/list=CON_OP_{code}\".format(code=code)\n    data = get(url, headers=http_header).content.decode('gbk')\n    data = data[data.find('\"') + 1: data.rfind('\"')].split(',')\n    fields = ['买量', '买价', '最新价', '卖价', '卖量', '持仓量', '涨幅', '行权价', '昨收价', '开盘价', '涨停价',\n              '跌停价', '申卖价五', '申卖量五', '申卖价四', '申卖量四', '申卖价三', '申卖量三', '申卖价二',\n              '申卖量二', '申卖价一', '申卖量一', '申买价一', '申买量一 ', '申买价二', '申买量二', '申买价三',\n              '申买量三', '申买价四', '申买量四', '申买价五', '申买量五', '行情时间', '主力合约标识', '状态码',\n              '标的证券类型', '标的股票', '期权合约简称', '振幅', '最高价', '最低价', '成交量', '成交额',\n              '分红调整标志', '昨结算价', '认购认沽标志', '到期日', '剩余天数', '虚实值标志', '内在价值', '时间价值']\n    result = list(zip(fields, data))\n    return result\n\n\ndef get_underlying_security_price(code='sh510050'):\n    url = \"http://hq.sinajs.cn/list=\" + code\n    data = get(url, headers=http_header).content.decode('gbk')\n    data = data[data.find('\"') + 1: data.rfind('\"')].split(',')\n    fields = ['证券简称', '今日开盘价', '昨日收盘价', '最近成交价', '最高成交价', '最低成交价', '买入价',\n              '卖出价', '成交数量', '成交金额', '买数量一', '买价位一', '买数量二', '买价位二', '买数量三',\n              '买价位三', '买数量四', '买价位四', '买数量五', '买价位五', '卖数量一', '卖价位一', '卖数量二',\n              '卖价位二', '卖数量三', '卖价位三', '卖数量四', '卖价位四', '卖数量五', '卖价位五', '行情日期',\n              '行情时间', '停牌状态']\n    return list(zip(fields, data))\n\n\ndef get_option_greek_alphabet(code):\n    url = \"http://hq.sinajs.cn/list=CON_SO_{code}\".format(code=code)\n    data = get(url, headers=http_header).content.decode('gbk')\n    data = data[data.find('\"') + 1: data.rfind('\"')].split(',')\n    fields = ['期权合约简称', '成交量', 'Delta', 'Gamma', 'Theta', 'Vega', '隐含波动率', '最高价', '最低价',\n              '交易代码', '行权价', '最新价', '理论价值']\n    return list(zip(fields, [data[0]] + data[4:]))\n\n\ndef get_option_time_line(code):\n    url = f\"https://stock.finance.sina.com.cn/futures/api/openapi.php/StockOptionDaylineService.getOptionMinline?\" \\\n          f\"symbol=CON_OP_{code}\"\n    data = get(url).json()['result']['data']\n    return data\n\n\ndef get_option_day_kline(code):\n    url = f\"http://stock.finance.sina.com.cn/futures/api/jsonp_v2.php//StockOptionDaylineService.getSymbolInfo?\" \\\n          f\"symbol=CON_OP_{code}\"\n    data = get(url).content\n    data = loads(data[data.find(b'(') + 1: data.rfind(b')')])\n    return data\n\n\ndef my_test():\n    dates = get_option_dates(cate='300ETF')\n    print('期权合约月份：{}'.format(dates))\n    for date in dates:\n        print('期权月份{}：到期日{} 剩余天数{}'.format(date, *get_option_expire_day(date, cate='300ETF')))\n    demo_code = '10002180'\n    for date in dates:\n        call_codes, put_codes = get_option_codes(date, underlying='510300')\n        print('期权月份{} 看涨期权代码：{}\\n期权月份{} 看跌期权代码：{}'.format(date, call_codes, date, put_codes))\n        demo_code = call_codes[0]\n    for index, i in enumerate(get_option_price(demo_code)):\n        print('期权' + demo_code, index, *i)\n    for index, i in enumerate(get_underlying_security_price(code='sh510300')):\n        print(index, *i)\n    for index, i in enumerate(get_option_greek_alphabet(demo_code)):\n        print('期权' + demo_code, index, *i)\n    time_line = get_option_time_line(demo_code)\n    for i in time_line[-10:]:\n        print('时间:{i}, 价格:{p}, 成交:{v}, 持仓:{t}, 均价:{a}'.format(**i))\n    day_kline = get_option_day_kline(demo_code)\n    for i in day_kline:\n        print('日期:{d}, 开盘:{o}, 最高:{h}, 最低:{l}, 收盘:{c}, 成交:{v}'.format(**i))\n\n\nif __name__ == '__main__':\n    my_test()\n"
  },
  {
    "path": "sina_future_kline_api.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport json\nimport requests\n\n\nURL_KLINE = \"https://stock2.finance.sina.com.cn/futures/api/jsonp.php//\" \\\n            \"InnerFuturesNewService.getDailyKLine?symbol={code}\"\n\n\ndef get_future_day_kline(code):\n    # 日期, 开, 高, 低, 收, 成交量, 持仓量\n    data = requests.get(URL_KLINE.format(code=code)).content\n    kline = json.loads(data[data.find(b'(') + 1: data.rfind(b')')])\n    # for i in kline:\n    #     print(i)\n    # print(type(kline[0]['o']))\n    return kline\n\n\nif __name__ == '__main__':\n    get_future_day_kline('M2005')\n\n"
  },
  {
    "path": "sina_stock_kline_api.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\n# 股票K线接口代码copy自AkShare项目https://github.com/jindaxiang/akshare\nimport re\nimport base64\nimport struct\nimport requests\nimport execjs\n\n\nhttp_header = {\n    'User-Agent': \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) \"\n                  \"Chrome/97.0.4692.71 Safari/537.36\",\n    'Referer': \"https://stock.finance.sina.com.cn/\",\n}\n\n\nhk_js_decode = \"\"\"\nfunction d(t) {\n    var e, i, n, r, a, o, s, l = (arguments,\n            864e5), u = 7657, c = [], h = [], d = ~(3 << 30), f = 1 << 30,\n        p = [0, 3, 5, 6, 9, 10, 12, 15, 17, 18, 20, 23, 24, 27, 29, 30], m = Math, g = function () {\n            var l, u;\n            for (l = 0; 64 > l; l++)\n                h[l] = m.pow(2, l),\n                26 > l && (c[l] = v(l + 65),\n                    c[l + 26] = v(l + 97),\n                10 > l && (c[l + 52] = v(l + 48)));\n            for (c.push(\"+\", \"/\"),\n                     c = c.join(\"\"),\n                     i = t.split(\"\"),\n                     n = i.length,\n                     l = 0; n > l; l++)\n                i[l] = c.indexOf(i[l]);\n            return r = {},\n                e = o = 0,\n                a = {},\n                u = w([12, 6]),\n                s = 63 ^ u[1],\n            {\n                _1479: T,\n                _136: _,\n                _200: S,\n                _139: k,\n                _197: _mi_run\n            }[\"_\" + u[0]] || function () {\n                return []\n            }\n        }, v = String.fromCharCode, b = function (t) {\n            return t === {}._\n        }, N = function () {\n            var t, e;\n            for (t = y(),\n                     e = 1; ;) {\n                if (!y())\n                    return e * (2 * t - 1);\n                e++\n            }\n        }, y = function () {\n            var t;\n            return e >= n ? 0 : (t = i[e] & 1 << o,\n                o++,\n            o >= 6 && (o -= 6,\n                e++),\n                !!t)\n        }, w = function (t, r, a) {\n            var s, l, u, c, d;\n            for (l = [],\n                     u = 0,\n                 r || (r = []),\n                 a || (a = []),\n                     s = 0; s < t.length; s++)\n                if (c = t[s],\n                    u = 0,\n                    c) {\n                    if (e >= n)\n                        return l;\n                    if (t[s] <= 0)\n                        u = 0;\n                    else if (t[s] <= 30) {\n                        for (; d = 6 - o,\n                                   d = c > d ? d : c,\n                                   u |= (i[e] >> o & (1 << d) - 1) << t[s] - c,\n                                   o += d,\n                               o >= 6 && (o -= 6,\n                                   e++),\n                                   c -= d,\n                                   !(0 >= c);)\n                            ;\n                        r[s] && u >= h[t[s] - 1] && (u -= h[t[s]])\n                    } else\n                        u = w([30, t[s] - 30], [0, r[s]]),\n                        a[s] || (u = u[0] + u[1] * h[30]);\n                    l[s] = u\n                } else\n                    l[s] = 0;\n            return l\n        }, x = function (t) {\n            var e, i, n;\n            for (t > 1 && (e = 0),\n                     e = 0; t > e; e++)\n                r.d++,\n                    n = r.d % 7,\n                (3 == n || 4 == n) && (r.d += 5 - n);\n            return i = new Date,\n                i.setTime((u + r.d) * l),\n                i\n        }, S = function () {\n            var t, i, a, o, l;\n            if (s >= 1)\n                return [];\n            for (r.d = w([18], [1])[0] - 1,\n                     a = w([3, 3, 30, 6]),\n                     r.p = a[0],\n                     r.ld = a[1],\n                     r.cd = a[2],\n                     r.c = a[3],\n                     r.m = m.pow(10, r.p),\n                     r.pc = r.cd / r.m,\n                     i = [],\n                     t = 0; o = {\n                d: 1\n            },\n                 y() && (a = w([3])[0],\n                     0 == a ? o.d = w([6])[0] : 1 == a ? (r.d = w([18])[0],\n                         o.d = 0) : o.d = a),\n                     l = {\n                         day: x(o.d)\n                     },\n                 y() && (r.ld += N()),\n                     a = w([3 * r.ld], [1]),\n                     r.cd += a[0],\n                     l.close = r.cd / r.m,\n                     i.push(l),\n                 !(e >= n) && (e != n - 1 || 63 & (r.c ^ t + 1)); t++)\n                ;\n            return i[0].prevclose = r.pc,\n                i\n        }, _ = function () {\n            var t, i, a, o, l, u, c, h, d, f, p;\n            if (s > 2)\n                return [];\n            for (c = [],\n                     d = {\n                         v: \"volume\",\n                         p: \"price\",\n                         a: \"avg_price\"\n                     },\n                     r.d = w([18], [1])[0] - 1,\n                     h = {\n                         day: x(1)\n                     },\n                     a = w(1 > s ? [3, 3, 4, 1, 1, 1, 5] : [4, 4, 4, 1, 1, 1, 3]),\n                     t = 0; 7 > t; t++)\n                r[[\"la\", \"lp\", \"lv\", \"tv\", \"rv\", \"zv\", \"pp\"][t]] = a[t];\n            for (r.m = m.pow(10, r.pp),\n                     s >= 1 ? (a = w([3, 3]),\n                         r.c = a[0],\n                         a = a[1]) : (a = 5,\n                         r.c = 2),\n                     r.pc = w([6 * a])[0],\n                     h.pc = r.pc / r.m,\n                     r.cp = r.pc,\n                     r.da = 0,\n                     r.sa = r.sv = 0,\n                     t = 0; !(e >= n) && (e != n - 1 || 7 & (r.c ^ t)); t++) {\n                for (l = {},\n                         o = {},\n                         f = r.tv ? y() : 1,\n                         i = 0; 3 > i; i++)\n                    if (p = [\"v\", \"p\", \"a\"][i],\n                    (f ? y() : 0) && (a = N(),\n                        r[\"l\" + p] += a),\n                        u = \"v\" == p && r.rv ? y() : 1,\n                        a = w([3 * r[\"l\" + p] + (\"v\" == p ? 7 * u : 0)], [!!i])[0] * (u ? 1 : 100),\n                        o[p] = a,\n                    \"v\" == p) {\n                        if (!(l[d[p]] = a) && (s > 1 || 241 > t) && (r.zv ? !y() : 1)) {\n                            o.p = 0;\n                            break\n                        }\n                    } else\n                        \"a\" == p && (r.da = (1 > s ? 0 : r.da) + o.a);\n                r.sv += o.v,\n                    l[d.p] = (r.cp += o.p) / r.m,\n                    r.sa += o.v * r.cp,\n                    l[d.a] = b(o.a) ? t ? c[t - 1][d.a] : l[d.p] : r.sv ? ((m.floor((r.sa * (2e3 / r.m) + r.sv) / r.sv) >> 1) + r.da) / 1e3 : l[d.p] + r.da / 1e3,\n                    c.push(l)\n            }\n            return c[0].date = h.day,\n                c[0].prevclose = h.pc,\n                c\n        }, T = function () {\n            var t, e, i, n, a, o, l;\n            if (s >= 1)\n                return [];\n            for (r.lv = 0,\n                     r.ld = 0,\n                     r.cd = 0,\n                     r.cv = [0, 0],\n                     r.p = w([6])[0],\n                     r.d = w([18], [1])[0] - 1,\n                     r.m = m.pow(10, r.p),\n                     a = w([3, 3]),\n                     r.md = a[0],\n                     r.mv = a[1],\n                     t = []; a = w([6]),\n                     a.length;) {\n                if (i = {\n                    c: a[0]\n                },\n                    n = {},\n                    i.d = 1,\n                32 & i.c)\n                    for (; ;) {\n                        if (a = w([6])[0],\n                        63 == (16 | a)) {\n                            l = 16 & a ? \"x\" : \"u\",\n                                a = w([3, 3]),\n                                i[l + \"_d\"] = a[0] + r.md,\n                                i[l + \"_v\"] = a[1] + r.mv;\n                            break\n                        }\n                        if (32 & a) {\n                            o = 8 & a ? \"d\" : \"v\",\n                                l = 16 & a ? \"x\" : \"u\",\n                                i[l + \"_\" + o] = (7 & a) + r[\"m\" + o];\n                            break\n                        }\n                        if (o = 15 & a,\n                            0 == o ? i.d = w([6])[0] : 1 == o ? (r.d = o = w([18])[0],\n                                i.d = 0) : i.d = o,\n                            !(16 & a))\n                            break\n                    }\n                n.date = x(i.d);\n                for (o in {\n                    v: 0,\n                    d: 0\n                })\n                    b(i[\"x_\" + o]) || (r[\"l\" + o] = i[\"x_\" + o]),\n                    b(i[\"u_\" + o]) && (i[\"u_\" + o] = r[\"l\" + o]);\n                for (i.l_l = [i.u_d, i.u_d, i.u_d, i.u_d, i.u_v],\n                         l = p[15 & i.c],\n                     1 & i.u_v && (l = 31 - l),\n                     16 & i.c && (i.l_l[4] += 2),\n                         e = 0; 5 > e; e++)\n                    l & 1 << 4 - e && i.l_l[e]++,\n                        i.l_l[e] *= 3;\n                i.d_v = w(i.l_l, [1, 0, 0, 1, 1], [0, 0, 0, 0, 1]),\n                    o = r.cd + i.d_v[0],\n                    n.open = o / r.m,\n                    n.high = (o + i.d_v[1]) / r.m,\n                    n.low = (o - i.d_v[2]) / r.m,\n                    n.close = (o + i.d_v[3]) / r.m,\n                    a = i.d_v[4],\n                \"number\" == typeof a && (a = [a, a >= 0 ? 0 : -1]),\n                    r.cd = o + i.d_v[3],\n                    l = r.cv[0] + a[0],\n                    r.cv = [l & d, r.cv[1] + a[1] + !!((r.cv[0] & d) + (a[0] & d) & f)],\n                    n.volume = (r.cv[0] & f - 1) + r.cv[1] * f,\n                    t.push(n)\n            }\n            return t\n        }, k = function () {\n            var t, e, i, n;\n            if (s > 1)\n                return [];\n            for (r.l = 0,\n                     n = -1,\n                     r.d = w([18])[0] - 1,\n                     i = w([18])[0]; r.d < i;)\n                e = x(1),\n                    0 >= n ? (y() && (r.l += N()),\n                        n = w([3 * r.l], [0])[0] + 1,\n                    t || (t = [e],\n                        n--)) : t.push(e),\n                    n--;\n            return t\n        };\n    return _mi_run = function () {\n        var t, i, a, o;\n        if (s >= 1)\n            return [];\n        for (r.f = w([6])[0],\n                 r.c = w([6])[0],\n                 a = [],\n                 r.dv = [],\n                 r.dl = [],\n                 t = 0; t < r.f; t++)\n            r.dv[t] = 0,\n                r.dl[t] = 0;\n        for (t = 0; !(e >= n) && (e != n - 1 || 7 & (r.c ^ t)); t++) {\n            for (o = [],\n                     i = 0; i < r.f; i++)\n                y() && (r.dl[i] += N()),\n                    r.dv[i] += w([3 * r.dl[i]], [1])[0],\n                    o[i] = r.dv[i];\n            a.push(o)\n        }\n        return a\n    }\n        ,\n        g()()\n}\n\"\"\"\n\nzh_sina_a_stock_hist_url = \"https://finance.sina.com.cn/realstock/company/{}/hisdata/klc_kl.js\"\njs_code = execjs.compile(hk_js_decode)\n\n\ndef get_stock_day_kline(code):\n    res = requests.get(zh_sina_a_stock_hist_url.format(code))\n    dict_list = js_code.call('d', res.text.split(\"=\")[1].split(\";\")[0].replace('\"', \"\"))\n    return dict_list\n\n\nURL_EX = \"http://stock.finance.sina.com.cn/fundInfo/api/openapi.php/FundPageInfoService.tabfh?symbol={code}&format=json\"\n\n\ndef get_ex_data(code):\n    tmp = code[2:] if code[:2] in ('sh', 'sz') else code\n    data = requests.get(URL_EX.format(code=tmp)).json()['result']['data']['fhdata']\n    # print(data)\n    return data\n\n\ndef get_1minutes(t=(('9:30:00', '11:30:00'), ('13:00:00', '15:00:00'))):\n    # t = [('9:30:00', '11:30:00'), ('13:00:00', '15:00:00')]\n    res, result = [], []\n    for begin, end in t:\n        b = begin.split(':')\n        b = int(b[0]) * 60 + int(b[1])\n        e = end.split(':')\n        e = int(e[0]) * 60 + int(e[1])\n        res.extend(list(range(b, e + 1)))\n    for index, i in enumerate(res):\n        hour, minute = divmod(i, 60)\n        result.append(':'.join([str(hour).rjust(2, '0'), str(minute).rjust(2, '0'), '00']))\n    return result\n\n\ndef get_stock_time_line(code):\n    \"\"\"股票分时线（1分钟线）\"\"\"\n    minutes = get_1minutes()\n    content = requests.get(f'http://hq.sinajs.cn/list=ml_{code}', headers=http_header).content.decode()\n    patt = re.compile(r'\\\"(.*)\\\"')\n    m = patt.search(content)\n    start = m.start() + 1\n    end = m.end() - 1\n    result = []\n    n = 0\n    while start < end:\n        tmp = (content[start:start+16])\n        start += 16\n        b = base64.b64decode(tmp)\n        avg = struct.unpack('<L', bytes(b[:4]))[0] / 1000.0\n        price = struct.unpack('<L', bytes(b[4:8]))[0] / 1000.0\n        amount = struct.unpack('<L', bytes(b[8:12]))[0]\n        if price < 1000000.0:\n            result.append((avg, price, amount, minutes[n]))\n            n += 1\n    return result\n\n\ndef my_test():\n    # kline = get_stock_day_kline('sh510050')\n    # for i in kline:\n    #     print(i)\n    for i in get_stock_time_line('sz000009'):\n        print(i)\n\n\nif __name__ == '__main__':\n    my_test()\n    # get_ex_data('sh510050')\n"
  },
  {
    "path": "time_line_iv.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport math\nfrom io import BytesIO\nimport matplotlib.pyplot as plt\nfrom sina_etf_option_api import get_option_time_line as get_etf_option_time_line\nfrom sina_stock_kline_api import get_stock_time_line, get_1minutes\nimport european_option as european_option\n\n\nSPOT_CODE_MAP = {\n    '510050': 'sh510050',\n    '510300': 'sh510300',\n}\n\n\ndef get_data(option_code, spot_code):\n    option_line = get_etf_option_time_line(option_code)\n    spot_line = get_stock_time_line(spot_code)\n    return option_line, spot_line\n\n\ndef time_str_to_int(time_str):\n    return int(''.join(time_str.split(':')[:2]))\n\n\ndef align_line(option_line, spot_line):\n    times, option_price, spot_price = [], [], []\n    if not option_line or not spot_line:\n        return times, option_price, spot_price\n    index = 0\n    len_option_line = len(option_line)\n    for i in spot_line:\n        spot_time = time_str_to_int(i[3])\n        option_time = time_str_to_int(option_line[index]['i'])\n        while spot_time > option_time and index < len_option_line - 1:\n            index += 1\n            # print('#########', len(option_line), len(spot_line), index)\n            option_time = time_str_to_int(option_line[index]['i'])\n        if spot_time == option_time:\n            times.append(i[3])\n            spot_price.append(i[1] if i[1] > 0.00001 else math.nan)\n            tmp_price = float(option_line[index]['p'])\n            option_price.append(tmp_price if tmp_price > 0.00001 else math.nan)\n    return times, option_price, spot_price\n\n\ndef cal_iv(option_price, spot_price, k, t, option_type):\n    iv_func = european_option.call_iv if option_type == 'Call' else european_option.put_iv\n    return [iv_func(i, j, k, t) if (i > 0.00001 and j > 0.00001) else math.nan for i, j in zip(option_price, spot_price)]\n\n\ndef draw_picture(times, option_price, spot_price, iv, option_code, show=True):\n    interval = math.ceil(len(times) / 20.0)\n    x = list(range(len(times)))\n    fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0}, figsize=(12.0, 5.7))\n    axs[0].plot(iv, color='r')\n    axs[0].set_xlim((x[0], x[-1]))\n    axs[0].set_ylabel('Implied Volatility')\n    axs[0].set_title(option_code)\n    axs[0].grid()\n    line1 = axs[1].plot(option_price, 'blue', label='option')\n    ax2 = axs[1].twinx()\n    line2 = ax2.plot(spot_price, 'orange', label='spot')\n    axs[1].set_xticks(x[::-interval][::-1])\n    axs[1].set_xticklabels(times[::-interval][::-1], rotation=60)\n    axs[1].set_ylabel('Price')\n    axs[1].grid()\n    lines = line1 + line2\n    line_labels = [i.get_label() for i in lines]\n    axs[1].legend(lines, line_labels, loc=0)\n    plt.tight_layout()\n    if show:\n        plt.show()\n    else:\n        buffer = BytesIO()\n        plt.savefig(buffer, format='png')\n        return buffer.getvalue()\n\n\ndef main(option_code, spot_code, k, t, option_type, show=True):\n    if spot_code in SPOT_CODE_MAP:\n        spot_code = SPOT_CODE_MAP[spot_code]\n    else:\n        return None\n    times, option_price, spot_price = align_line(*get_data(option_code, spot_code))\n    if times:\n        iv = cal_iv(option_price, spot_price, k, t, option_type)\n        return draw_picture(times, option_price, spot_price, iv, option_code, show)\n    else:\n        return None\n\n\nif __name__ == '__main__':\n    main('10002235', '510050', 3.0, 238.0 / 365.0, 'Call')\n\n"
  },
  {
    "path": "volatility_surface.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\n# python3\n\nfrom time import sleep\nfrom threading import Thread, Lock\n\nfrom requests import get, exceptions\nfrom numpy import polyfit, polyval, meshgrid, array, nan\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\nfrom mpl_toolkits.mplot3d import Axes3D\n\nimport sina_etf_option_api\n\n\nhttp_header = {\n    'User-Agent': \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) \"\n                  \"Chrome/97.0.4692.71 Safari/537.36\",\n    'Referer': \"https://stock.finance.sina.com.cn/\",\n}\n\nCOLORS = ['blue', 'yellow', 'lime', 'red', 'purple', 'slategray', 'tomato', 'orange', 'darkred', 'aqua']\nglobal_ax_lines_call = [{'ax': None, 'lines': []} for _ in range(5)]\nglobal_ax_lines_put = [{'ax': None, 'lines': []} for _ in range(5)]\nupdate_picture_lock = Lock()\nELEV = 30\nAZIM = 120\n\n\ndef requests_get(all_codes):\n    url = \"http://hq.sinajs.cn/list={codes}\".format(codes=all_codes)\n    while True:\n        try:\n            data = get(url, headers=http_header).content.decode('gbk').strip().split('\\n')\n            break\n        except (exceptions.ConnectionError, exceptions.ConnectTimeout) as e:\n            print('连接出错，10秒后重试')\n            print(e)\n            sleep(10)\n    return [i.split(',') for i in data]\n\n\ndef get_codes(cate, exchange, underlying, dividend):\n    while True:\n        try:\n            dates = sorted(sina_etf_option_api.get_option_dates(cate=cate, exchange=exchange))\n            call, put = [], []\n            for date in dates:\n                call_codes, put_codes = sina_etf_option_api.get_option_codes(date, underlying=underlying)\n                call.append(['CON_SO_' + i for i in call_codes])\n                put.append(['CON_SO_' + i for i in put_codes])\n            all_codes = ','.join([','.join(i) for i in call] + [','.join(i) for i in put])\n            data = requests_get(all_codes)\n            if dividend:\n                codes_tmp = [i[0][11:26] for i in data]  # 考虑分红\n            else:\n                codes_tmp = [i[0][11:26] for i in data if not i[0].endswith('A')]  # 不考虑分红\n            for i in range(len(call)):\n                call[i] = [j for j in call[i] if j in codes_tmp]\n                put[i] = [j for j in put[i] if j in codes_tmp]\n            break\n        except (exceptions.ConnectionError, exceptions.ConnectTimeout) as e:\n            print('连接出错，10秒后重试')\n            print(e)\n            sleep(10)\n    return call, put, ','.join(codes_tmp), dates\n\n\ndef get_data(call, put, all_codes):\n    implied_volatility, strike_price, vega, theta, gamma, delta = [], [], [], [], [], []\n    for line in requests_get(all_codes):\n        implied_volatility.append(float(line[9]))\n        vega.append(float(line[8]))\n        strike_price.append(float(line[13]))\n        theta.append(float(line[7]))\n        gamma.append(float(line[6]))\n        delta.append(float(line[5]))\n    call_implied_volatility, call_strike_price, call_vega, call_theta, call_gamma, call_delta = [], [], [], [], [], []\n    put_implied_volatility, put_strike_price, put_vega, put_theta, put_gamma, put_delta = [], [], [], [], [], []\n    b = 0\n    for i in call:\n        len_i = len(i)\n        call_implied_volatility.append(implied_volatility[b:b + len_i])\n        call_strike_price.append(strike_price[b:b + len_i])\n        call_vega.append(vega[b:b + len_i])\n        call_theta.append(theta[b:b + len_i])\n        call_gamma.append(gamma[b:b + len_i])\n        call_delta.append(delta[b:b + len_i])\n        b += len_i\n    for i in put:\n        len_i = len(i)\n        put_implied_volatility.append(implied_volatility[b:b + len_i])\n        put_strike_price.append(strike_price[b:b + len_i])\n        put_vega.append(vega[b:b + len_i])\n        put_theta.append(theta[b:b + len_i])\n        put_gamma.append(gamma[b:b + len_i])\n        put_delta.append(delta[b:b + len_i])\n        b += len_i\n    return call_strike_price, [call_delta, call_gamma, call_theta, call_vega, call_implied_volatility], \\\n        put_strike_price, [put_delta, put_gamma, put_theta, put_vega, put_implied_volatility]\n\n\ndef knockout_small_value(x, y):\n    length = len(x)\n    new_x = [x[i] for i in range(length) if y[i] > 0.01]\n    new_y = [i for i in y if i > 0.01]\n    return new_x, new_y\n\n\ndef fit(call_x, call_y, put_x, put_y):\n    xx = set()\n    for i in call_x:\n        xx |= set(i)\n    xx = sorted(xx)\n    call_y2, put_y2 = [], []\n    for i in range(len(call_x)):\n        if xx == call_x[i]:\n            call_y2.append(call_y[i])\n        else:\n            new_x, new_y = knockout_small_value(call_x[i], call_y[i])\n            tmp = polyval(polyfit(new_x, new_y, 2), xx)\n            tmp[tmp < 0.0] = 0.0\n            tmp_y, index_y = [], 0\n            for index, j in enumerate(xx):\n                if j in call_x[i]:\n                    tmp_y.append(call_y[i][index_y])\n                    index_y += 1\n                else:\n                    tmp_y.append(tmp[index])\n            call_y2.append(tmp_y)\n        if xx == put_x[i]:\n            put_y2.append(put_y[i])\n        else:\n            new_x, new_y = knockout_small_value(put_x[i], put_y[i])\n            tmp = polyval(polyfit(new_x, new_y, 2), xx)\n            tmp[tmp < 0.0] = 0.0\n            tmp_y, index_y = [], 0\n            for index, j in enumerate(xx):\n                if j in put_x[i]:\n                    tmp_y.append(put_y[i][index_y])\n                    index_y += 1\n                else:\n                    tmp_y.append(tmp[index])\n            put_y2.append(tmp_y)\n    return xx, call_y2, put_y2\n\n\ndef not_fit(call_x, call_y, put_x, put_y):\n    xx = set()\n    for i in call_x:\n        xx |= set(i)\n    xx = sorted(xx)\n    call_y2, put_y2 = [], []\n    for i in range(len(call_x)):\n        if xx == call_x[i]:\n            call_y2.append(call_y[i])\n        else:\n            tmp_y, index_y = [], 0\n            for index, j in enumerate(xx):\n                if j in call_x[i]:\n                    tmp_y.append(call_y[i][index_y])\n                    index_y += 1\n                else:\n                    tmp_y.append(nan)\n            call_y2.append(tmp_y)\n        if xx == put_x[i]:\n            put_y2.append(put_y[i])\n        else:\n            tmp_y, index_y = [], 0\n            for index, j in enumerate(xx):\n                if j in put_x[i]:\n                    tmp_y.append(put_y[i][index_y])\n                    index_y += 1\n                else:\n                    tmp_y.append(nan)\n            put_y2.append(tmp_y)\n    return xx, call_y2, put_y2\n\n\ndef update(call_codes, put_codes, all_codes, x, y, yy, surf_call, surf_put, ax_iv_sf_call, ax_iv_sf_put, is_fit):\n    azim = AZIM\n    while True:\n        # sleep(5)  # 每隔5秒刷新一次\n        sleep(10)\n        with update_picture_lock:\n            call_x, call_ys, put_x, put_ys = get_data(call_codes, put_codes, all_codes)\n            if is_fit:\n                xx, call_y2, put_y2 = fit(call_x, call_ys[-1], put_x, put_ys[-1])\n            else:\n                xx, call_y2, put_y2 = not_fit(call_x, call_ys[-1], put_x, put_ys[-1])\n            surf_call.remove()\n            azim += 15\n            if azim > 360:\n                azim -= 360\n            ax_iv_sf_call.view_init(ELEV, azim)\n            # surf_call = ax_iv_sf_call.plot_surface(x, y, array(call_y2), rstride=1, cstride=1, cmap='rainbow')\n            surf_call = ax_iv_sf_call.plot_wireframe(x, y, array(call_y2), rstride=1, cstride=1)\n            surf_put.remove()\n            ax_iv_sf_put.view_init(ELEV, azim)\n            # surf_put = ax_iv_sf_put.plot_surface(x, y, array(put_y2), rstride=1, cstride=1, cmap='rainbow')\n            surf_put = ax_iv_sf_put.plot_wireframe(x, y, array(put_y2), rstride=1, cstride=1)\n            for index in range(5):\n                for i in yy:\n                    global_ax_lines_call[index]['ax'].lines.remove(global_ax_lines_call[index]['lines'][i])\n                    global_ax_lines_put[index]['ax'].lines.remove(global_ax_lines_put[index]['lines'][i])\n                global_ax_lines_call[index]['lines'] = []\n                global_ax_lines_put[index]['lines'] = []\n            for index in range(5):\n                for i in yy:\n                    global_ax_lines_call[index]['lines'].append(global_ax_lines_call[index]['ax'].plot(call_x[i], array(call_ys[index][i]), COLORS[i])[0])\n                    global_ax_lines_put[index]['lines'].append(global_ax_lines_put[index]['ax'].plot(put_x[i], array(put_ys[index][i]), COLORS[i])[0])\n            plt.draw()\n\n\ndef main(cate, exchange, underlying, dividend=True, is_fit=True):\n    call_codes, put_codes, all_codes, dates = get_codes(cate, exchange, underlying, dividend)\n    dates_label = ',,'.join(dates).split(',')\n    call_x, call_ys, put_x, put_ys = get_data(call_codes, put_codes, all_codes)\n    if is_fit:\n        xx, call_y2, put_y2 = fit(call_x, call_ys[-1], put_x, put_ys[-1])\n    else:\n        xx, call_y2, put_y2 = not_fit(call_x, call_ys[-1], put_x, put_ys[-1])\n    yy = list(range(len(call_y2)))\n    x, y = meshgrid(xx, yy)\n    fig = plt.figure(figsize=(12, 5.7))\n    fig.canvas.mpl_connect('button_press_event', lambda event: update_picture_lock.acquire())\n    fig.canvas.mpl_connect('button_release_event', lambda event: update_picture_lock.release())\n    gs = gridspec.GridSpec(3, 6, figure=fig)\n    ylabels = ['Delta', 'Gamma', 'Theta', 'Vega', 'Implied Volatility']\n    call_gs = [gs[2:3, :1], gs[2:3, 1:2], gs[2:3, 2:3], gs[1:2, 2:3], gs[:1, 2:3]]\n    put_gs = [gs[2:3, 3:4], gs[2:3, 4:5], gs[2:3, 5:6], gs[1:2, 5:6], gs[:1, 5:6]]\n    # ---------------------------------------------------------------------------------------------------\n    for index in range(5):\n        call_ax = fig.add_subplot(call_gs[index])\n        for i in yy:\n            line, = call_ax.plot(call_x[i], call_ys[index][i], COLORS[i])\n            global_ax_lines_call[index]['lines'].append(line)\n        call_ax.set_xlabel('Strike Price')\n        call_ax.set_ylabel(ylabels[index])\n        call_ax.legend(dates, fontsize='xx-small')\n        global_ax_lines_call[index]['ax'] = call_ax\n        put_ax = fig.add_subplot(put_gs[index])\n        for i in yy:\n            line, = put_ax.plot(put_x[i], put_ys[index][i], COLORS[i])\n            global_ax_lines_put[index]['lines'].append(line)\n        put_ax.set_xlabel('Strike Price')\n        put_ax.set_ylabel(ylabels[index])\n        put_ax.legend(dates, fontsize='xx-small')\n        global_ax_lines_put[index]['ax'] = put_ax\n    ax_iv_sf_call = fig.add_subplot(gs[:2, :2], projection='3d')\n    ax_iv_sf_call.view_init(ELEV, AZIM)\n    # surf_call = ax_iv_sf_call.plot_surface(x, y, array(call_y2), rstride=1, cstride=1, cmap='rainbow')\n    # print(x.shape, y.shape, array(call_y2).shape)\n    surf_call = ax_iv_sf_call.plot_wireframe(x, y, array(call_y2), rstride=1, cstride=1, cmap='rainbow')\n    ax_iv_sf_call.set_yticklabels(dates_label)\n    ax_iv_sf_call.set_xlabel('Strike Price')\n    ax_iv_sf_call.set_ylabel('Expiration Date')\n    ax_iv_sf_call.set_zlabel('Implied Volatility')\n    ax_iv_sf_call.set_title('Call Option')\n    ax_iv_sf_put = fig.add_subplot(gs[:2, 3:5], projection='3d')\n    ax_iv_sf_put.view_init(ELEV, AZIM)\n    # surf_put = ax_iv_sf_put.plot_surface(x, y, array(put_y2), rstride=1, cstride=1, cmap='rainbow')\n    surf_put = ax_iv_sf_put.plot_wireframe(x, y, array(put_y2), rstride=1, cstride=1, cmap='rainbow')\n    ax_iv_sf_put.set_yticklabels(dates_label)\n    ax_iv_sf_put.set_xlabel('Strike Price')\n    ax_iv_sf_put.set_ylabel('Expiration Date')\n    ax_iv_sf_put.set_zlabel('Implied Volatility')\n    ax_iv_sf_put.set_title('Put Option')\n    plt.tight_layout()\n    thread = Thread(target=update, args=(call_codes, put_codes, all_codes, x, y, yy, surf_call, surf_put, ax_iv_sf_call, ax_iv_sf_put, is_fit))\n    thread.setDaemon(True)\n    thread.start()\n    plt.show()\n\n\nif __name__ == '__main__':\n    category = '50ETF'\n    underlying_security = '510050'\n    # category = '300ETF'\n    # underlying_security = '510300'\n    main(cate=category, exchange='null', underlying=underlying_security, dividend=False, is_fit=True)\n"
  },
  {
    "path": "volatility_surface2.py",
    "content": "\"\"\"\nAuthor: shifulin\nEmail: shifulin666@qq.com\n\"\"\"\nimport time\nfrom threading import Thread, Lock\nfrom collections import namedtuple\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\nfrom mpl_toolkits.mplot3d import Axes3D\n\nfrom sina_commodity_option_api import get_000300_price, get_t_quotation\nimport european_option\n\n# EUROPEAN_OPTION = {'io', 'cu', 'au'}\nOptionInfo = namedtuple('OptionInfo', ['x', 'y', 'k', 't', 'type'])\n\n\nclass VolSurface(object):\n    def __init__(self, expiry_date_map):\n        self.spot = 'io'\n        self.expiry_date_map = expiry_date_map\n        self.x = np.array([[[]]])\n        self.y = np.array([[[]]])\n        self.data = np.array([[[]]])\n        self.code_to_info = {}\n        self.strike_prices = []\n        self.expiry_dates = []\n        self.x_index = []\n        self.spot_price = 0.0\n        self.update_picture_lock = Lock()\n        self.elev = 30\n        self.azim = 120\n        self.colors = ['blue', 'yellow', 'lime', 'red', 'purple', 'slategray', 'tomato', 'orange', 'darkred', 'aqua']\n        self.init()\n        self.lines = {}\n        self.update_price(self.get_spot_price(), self.get_option_price())\n\n    @staticmethod\n    def get_spot_price():\n        return float(get_000300_price()[3])\n\n    def get_option_price(self):\n        result = []\n        for i in self.expiry_date_map:\n            up, down = get_t_quotation(self.spot + i)\n            result.extend(up)\n            result.extend(down)\n        return result\n\n    def update_price(self, spot_price, option_price):\n        self.spot_price = spot_price\n        for i in option_price:\n            price = (float(i[1]) + float(i[3])) / 2.0\n            x, y, k, t, option_type = self.code_to_info[i[-1]]\n            if option_type == 'Call':\n                index = 0\n                iv_func = european_option.call_iv\n            else:\n                index = 5\n                iv_func = european_option.put_iv\n            self.data[x, y, index] = price\n            iv = iv_func(price, spot_price, k, t)\n            delta, gamma, theta, vega = european_option.greeks(spot_price, k, iv, 0.03, t, option_type)\n            self.data[x, y, index] = delta\n            self.data[x, y, index + 1] = gamma\n            self.data[x, y, index + 2] = theta\n            self.data[x, y, index + 3] = vega\n            self.data[x, y, index + 4] = iv\n\n    def init(self):\n        strike_prices, expiry_dates = set(), set()\n        data = self.get_option_price()\n        for i in data:\n            strike_prices.add(i[7])\n            expiry_dates.add(i[-1][2:6])\n        self.strike_prices = sorted(strike_prices, key=lambda i: float(i))\n        self.expiry_dates = sorted(expiry_dates, key=lambda i: int(i))\n        self.x_index = [float(i) for i in self.strike_prices]\n        strike_prices = {j: i for i, j in enumerate(self.strike_prices)}\n        expiry_dates = {j: i for i, j in enumerate(self.expiry_dates)}\n        for i in data:\n            x = strike_prices[i[7]]\n            y = expiry_dates[i[-1][2:6]]\n            k = float(i[7])\n            t = float(self.expiry_date_map[i[-1][2:6]]) / 365.0\n            option_type = 'Call' if 'C' in i[-1] else 'Put'\n            self.code_to_info[i[-1]] = OptionInfo(x, y, k, t, option_type)\n        self.x, self.y = np.meshgrid(list(range(len(expiry_dates))), [float(i) for i in strike_prices])\n        self.data = np.ones(self.x.shape + (10, ))\n        for i in self.code_to_info.values():\n            self.data[i.x, i.y, :] = 0.0\n        self.data[self.data > 0.5] = np.nan\n\n    def start_update_picture(self):\n        fig = plt.figure(figsize=(12, 5.7))\n        fig.canvas.mpl_connect('button_press_event', lambda event: self.update_picture_lock.acquire())\n        fig.canvas.mpl_connect('button_release_event', lambda event: self.update_picture_lock.release())\n        gs = gridspec.GridSpec(3, 6, figure=fig)\n        call_gs = [gs[2:3, :1], gs[2:3, 1:2], gs[2:3, 2:3], gs[1:2, 2:3], gs[:1, 2:3]]\n        put_gs = [gs[2:3, 3:4], gs[2:3, 4:5], gs[2:3, 5:6], gs[1:2, 5:6], gs[:1, 5:6]]\n        ylabels = ['Delta', 'Gamma', 'Theta', 'Vega', 'Implied Volatility']\n        m, n, _ = self.data.shape\n        for index in range(5):\n            call_ax = fig.add_subplot(call_gs[index])\n            tmp = []\n            for i in range(n):\n                line, = call_ax.plot(self.x_index, self.data[:, i, index], self.colors[i])\n                tmp.append(line)\n            self.lines[call_ax] = (index, tmp)\n            call_ax.set_xlabel('Strike Price')\n            call_ax.set_ylabel(ylabels[index])\n            call_ax.legend(self.expiry_dates, fontsize='xx-small')\n            put_ax = fig.add_subplot(put_gs[index])\n            tmp = []\n            for i in range(n):\n                line, = put_ax.plot(self.x_index, self.data[:, i, index + 5], self.colors[i])\n                tmp.append(line)\n            self.lines[put_ax] = (index + 5, tmp)\n            put_ax.set_xlabel('Strike Price')\n            put_ax.set_ylabel(ylabels[index])\n            put_ax.legend(self.expiry_dates, fontsize='xx-small')\n        ax_iv_sf_call = fig.add_subplot(gs[:2, :2], projection='3d')\n        self.surf_call = ax_iv_sf_call.plot_wireframe(self.x, self.y, self.data[:, :, 4], rstride=1, cstride=1)\n        ax_iv_sf_call.set_yticklabels(self.expiry_dates)\n        ax_iv_sf_call.set_xlabel('Strike Price')\n        ax_iv_sf_call.set_ylabel('Expiration Date')\n        ax_iv_sf_call.set_zlabel('Implied Volatility')\n        ax_iv_sf_call.set_title('Call Option')\n        ax_iv_sf_call.view_init(self.elev, self.azim)\n        ax_iv_sf_put = fig.add_subplot(gs[:2, 3:5], projection='3d')\n        self.surf_put = ax_iv_sf_put.plot_wireframe(self.x, self.y, self.data[:, :, 9], rstride=1, cstride=1)\n        ax_iv_sf_put.set_yticklabels(self.expiry_dates)\n        ax_iv_sf_put.set_xlabel('Strike Price')\n        ax_iv_sf_put.set_ylabel('Expiration Date')\n        ax_iv_sf_put.set_zlabel('Implied Volatility')\n        ax_iv_sf_put.set_title('Put Option')\n        ax_iv_sf_put.view_init(self.elev, self.azim)\n\n        def update_picture():\n            while True:\n                with self.update_picture_lock:\n                    self.azim += 15\n                    if self.azim > 360:\n                        self.azim -= 360\n                    for k, v in self.lines.items():\n                        index, lines = v\n                        [k.lines.remove(lines[i]) for i in range(n)]\n                        tmp = []\n                        for i in range(n):\n                            line, = k.plot(self.x_index, self.data[:, i, index], self.colors[i])\n                            tmp.append(line)\n                        self.lines[k] = (index, tmp)\n                    self.surf_call.remove()\n                    self.surf_call = ax_iv_sf_call.plot_wireframe(self.x, self.y, self.data[:, :, 4], rstride=1, cstride=1)\n                    ax_iv_sf_call.view_init(self.elev, self.azim)\n                    self.surf_put.remove()\n                    self.surf_put = ax_iv_sf_put.plot_wireframe(self.x, self.y, self.data[:, :, 9], rstride=1, cstride=1)\n                    ax_iv_sf_put.view_init(self.elev, self.azim)\n                    plt.draw()\n                    plt.tight_layout()\n                time.sleep(5)\n                self.update_price(self.get_spot_price(), self.get_option_price())\n        t = Thread(target=update_picture)\n        t.setDaemon(True)\n        t.start()\n        plt.show()\n\n    def draw_picture(self):\n        pass\n\n\ndef main():\n    expiry_date_map = {\n        '2002': 33,\n        '2003': 61,\n        '2004': 89,\n        '2006': 152,\n        '2009': 243,\n        '2012': 334,\n    }\n    vs = VolSurface(expiry_date_map)\n    vs.start_update_picture()\n\n\nif __name__ == '__main__':\n    main()\n"
  }
]