Skip to content

Commit

Permalink
Add cost to borrow of stocks. Data from IBKR (#1663)
Browse files Browse the repository at this point in the history
* add ctb to dps

* add test for ctb

* reformat using black

* fix tests for ctb

Co-authored-by: didierlopes.eth <[email protected]>
Co-authored-by: jmaslek <[email protected]>
  • Loading branch information
3 people authored Apr 15, 2022
1 parent 6535b1d commit 73187d9
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 41 deletions.
1 change: 1 addition & 0 deletions openbb_terminal/stocks/dark_pool_shorts/dps_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# pylint: disable=unused-import

# Menu commands
from .ibkr_view import display_cost_to_borrow as call_ctb
from .yahoofinance_view import display_most_shorted as call_shorted
from .shortinterest_view import high_short_interest as call_hsi
from .finra_view import darkpool_otc as call_prom
Expand Down
33 changes: 33 additions & 0 deletions openbb_terminal/stocks/dark_pool_shorts/dps_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
shortinterest_view,
stockgrid_view,
yahoofinance_view,
ibkr_view,
)

logger = logging.getLogger(__name__)
Expand All @@ -41,6 +42,7 @@ class DarkPoolShortsController(StockBaseController):
CHOICES_COMMANDS = [
"load",
"shorted",
"ctb",
"hsi",
"prom",
"pos",
Expand Down Expand Up @@ -82,6 +84,8 @@ def print_help(self):
[src][Yahoo Finance][/src]
shorted show most shorted stocks
[src][Interactive Broker][/src]
ctb stocks with highest cost to borrow
[src][Shortinterest.com][/src]
hsi show top high short interest stocks of over 20% ratio
[src][FINRA][/src]
Expand Down Expand Up @@ -134,6 +138,35 @@ def call_shorted(self, other_args: List[str]):
export=ns_parser.export,
)

@log_start_end(log=logger)
def call_ctb(self, other_args: List[str]):
"""Process CTB command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="ctb",
description="Print stocks with highest cost to borrow. [Source: Interactive Broker]",
)
parser.add_argument(
"-n",
"--number",
action="store",
dest="number",
type=check_int_range(1, 10000),
default=20,
help="Number of stocks with high cost to borrow to retrieve.",
)
if other_args and "-" not in other_args[0][0]:
other_args.insert(0, "-l")
ns_parser = parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED
)
if ns_parser:
ibkr_view.display_cost_to_borrow(
num_stocks=ns_parser.number,
export=ns_parser.export,
)

@log_start_end(log=logger)
def call_hsi(self, other_args: List[str]):
"""Process hsi command"""
Expand Down
38 changes: 38 additions & 0 deletions openbb_terminal/stocks/dark_pool_shorts/ibkr_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
""" Interactive Broker Model """
__docformat__ = "numpy"

import logging

import ftplib
from io import BytesIO
import pandas as pd

from openbb_terminal.decorators import log_start_end

logger = logging.getLogger(__name__)


@log_start_end(log=logger)
def get_cost_to_borrow() -> pd.DataFrame:
"""Get stocks with highest cost to borrow [Source: Interactive Broker]
Returns
-------
pd.DataFrame
Cost to borrow
"""
ftp = ftplib.FTP("ftp3.interactivebrokers.com", "shortstock")

flo = BytesIO()
ftp.retrbinary("RETR usa.txt", flo.write)
flo.seek(0)

data = pd.read_csv(flo, sep="|", skiprows=1)
data = data[["#SYM", "FEERATE", "AVAILABLE"]]
data["AVAILABLE"] = data["AVAILABLE"].replace(">10000000", 10000000)
data.fillna(0, inplace=True)
data["AVAILABLE"] = data["AVAILABLE"].astype(int)
data.sort_values(by=["FEERATE"], ascending=False, inplace=True)
data["FEERATE"] = data["FEERATE"].apply(lambda x: str(x) + "%")
data.columns = ["Symbol", "Fees", "Available"]
return data
44 changes: 44 additions & 0 deletions openbb_terminal/stocks/dark_pool_shorts/ibkr_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
""" Interactive Broker View """
__docformat__ = "numpy"

import logging
import os

from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import export_data, print_rich_table
from openbb_terminal.rich_config import console
from openbb_terminal.stocks.dark_pool_shorts import ibkr_model

logger = logging.getLogger(__name__)


@log_start_end(log=logger)
def display_cost_to_borrow(num_stocks: int, export: str):
"""Display stocks with highest cost to borrow. [Source: Interactive Broker]
Parameters
----------
num_stocks: int
Number of stocks to display
export : str
Export dataframe data to csv,json,xlsx file
"""
df = ibkr_model.get_cost_to_borrow().head(num_stocks)

if df.empty:
console.print("No data found.")
else:
print_rich_table(
df,
headers=list(df.columns),
show_index=False,
title="Highest Cost to Borrow",
)
console.print("")

export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"cost_to_borrow",
df,
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,56 @@ interactions:
response:
body:
string: !!binary |
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
x+KLFAAA
H4sIAAAAAAAAAO1YTXMbNxL9LzxzEXx/+JZabyVblbi8a+WQcrm2GImWuZFILUk50br03/O6MZCm
e1zZyx51GQ4xQKPx0P36AV9Wl582x/Pq1ZfVcXu6v8Hb+y+r2+15Q02X98fjdn/5sHq1+und69V6
dXq4/eVwg78X7374Fv+3v2P4/nr7ZnO7ReubH9+hcbc/nY/3t9v9+eLhjpr/9o+f/n7xM7583B1P
54vj5mr7enPGF+dLqa56a9eY/vr+ZnP8cXP8dXu+2JE9l2Mrtnib1qvr2/Ph48fTFg7+xcVII87o
9N/Dnmd4fTHz5mL6MHn17e32uLvcfPNm+9u/fj4cf12pyd7iK/q1kkwL6w7I2+P28+5wf/rrzeFE
33w2za9Xd9T1+90eXuBfh4cXtNtfv8UshyuC7e64pZ+lf/uraVHF8ppPZ8aem5LlRS3W+fjk7f+w
2ULWNqdpvmbz7nA6/7nBaqvVBqc5lgZh8Wpz3nx33OzJ1d2ZYsZdEdS0I/iD18+bm93VP+n/CWHW
Pyd6uNsDnoGfmZ/uAQ9Pj0QPZ+n5cKbOt5vfVx8e+/bDt9s72HI5tJwT+UuvJbnIr3g6m8crgml6
dTWMDj5jpf01uzRaC7qM18oBSq+1xGGsZTcZc97bqYMLNufx2sLoEEub7LqU02QXYZ9Gh+aGv661
MnXwtsbJrndlrMInl0drhvPjtbbJGFJqrCLYMPwNzg9/g7dldPAtTLMFvEx2AxAcHYof/oZKC51e
Wx12Wx2riD4Of2Ft+BujG6jHZAfqMdWBeqxxuB5bGK4n68cGJGfHBiTXxoISeo7W7AfqqbiBeipt
rCLbNPzNLg5/sw8D9RzcQB1bO1aRcx7+5hKHv7mGsQG5+bEBWONYRfF5OFlCGqgXYDkZK8kP1Aui
aDJWah7+lpYG6hXeTB2A/1hF9W6sosLy6JDyQL2yR/21hLGKWt1YRbNl+NtcHqg3RNfogICY7Dbs
7GS3YfXo8IFI/gqcej4cT8Qi/7k/EJ+jdFx2wnzPjIlorr45i7D36xa8SeRVCR4RXeu6tmZozRaR
g63gPtUk7KBvHlOVtAZ81QCZ1pJzxfWmXAy8sS2Ar7HJPJTaazXYEyoZFvHOLdm4Ou9SrAkYgyz0
o0/Khjb/eUp4rVtiM4hYMQyTUU/hVzTKUwIhYRx85f/pq4PmENBsNhvvxDqCM9hcDE+TITgEo0g+
RFjqSwvWcLS1krkFsxiixGfLcMR47IBrie22CATF3OAsQNtcVT5hVrTAJaRMpMFr7KtBA6h2OFVj
NiHOW1AtTJkvpGEd9GPJM2GtOUPJ6CJFNI/1wYCpZtGCkDUUyeA6JH+mFu/J28BPG03C7LUU3jZE
V6a1AGRT8hwWDIoenvtcEtSH71O1+eS16KUgtwzKH9InckggA2WgFuyjDczevgRQ5BoRZMoM7Wqb
iuSKaJSuIG9NUH0wSjoXmvFVzISsUS2EBhwA94JoucXrOKsIxjZPFzbT5hCCiBQOJWftoHXawWiN
9zOsCrASoUIBIBFvwNOJkGiU3jPEYcA4FfIuKI7BjzVZBBLGwEGV87CVsArUALjebdF0wLBZH6Zx
pSi3kfRR8wDqiUHhmmc05vPziEO2qhgEERTdx8POfH6Wo/PgAOl+Ptzck6R970sChuBkcHvB4kGH
UCkZ0bZGbWHpsaaSzwUuoDSxYvahOAratQdMLO7gsesvKVdLn1xIhUrDGtIhcpnCFI7Ezprsc6EN
1nUt4KtNkTuj8HBFIi3kuDPc4lKM9LWBJ4UeqfzJ+8jlFtUGxZAdQ2XxPCnKJ41KNoECeYqa2Wd0
6VUREwbitTVg9yTp8Anw2D5Fl1qYguQP+exrYldjilzbsHGBqifKWWNFuHYl9roI56Pvo1LkWush
fxJ3Rt9eJYtttQMemu+jagjsainZsz+OSjx5CELmqu8RtImBIs7oaICI+gvKMsMCLB276kMI3eeu
LAj51l1txff9gjct9c4xlWlzy7T2ymcJ6tn6KqCbwhQtHBKgCV8Y8IQMYDAt1tqHIwl5FOps7wM3
aukYIrh49paG2KboIjSs8x0E+NMxzM3xKPBSB4qEC2OIhA3dTua4QWh/2l1/ItnQosx6kLgsFcQU
uUnRgGym1NdVBeB7Yc0hSUk6oAbzD1iShUQytBxshK9TcaeSgs1wxkqagCjnkV/REZW/IK8MpV/C
djxVfV0q4VgyVRArfIqaphxWpBkosWekYyhLw2CvBOkBsKHHY5r8icAJ+4jdK09aStdIbIMSDUmR
Fzov4NbkXcFmXSMIBiV5QXqPuIJLDNf/3tGyOKA+RRRJko2ylAH9hWipMzjRAzBRnHvKDvIacgKi
kfLkaUupxlu2rmo/pA4WAJ2oSjOpwnkNw6JlbYSDJs4VgaMoJOUAr2ZVqtamfKHZxEj6L2QwOEdJ
t4q6KwUSwkfCTXonpTkwFVFBx53nDai0JWoZVm0SOF3r9OgnJWVZhcnIxfFAt7SiQEA02oU2jrLg
ocUp55BBRYHHeTKPGDSgcosKDC2swIIhjJqUPNXLWVY4pJQ+YZTWsywvZH+ENBaHDisPHaCym8Nv
fAByGhYIQCUR20J50olFnBAaksvKpAUocqM7H8gjQ4FfXjICxKWGJQEpEWhMJVrjIFWpogy2cZRM
ijDBlE7qGdtJmQ8U1TKeEJhIEyG7wNAaYiRpms1GKi/IGLAODgkE6LCDeRoROhQAZSKYTJwGIRsM
XYI80wQmoLimkwykrpcrqNlr3C3NQfmsjkJYHWmMJ6EPMCAu5kdfcEVxkqGiivXm+biCI5pKx7RI
0MWmcRxJvkPpkoutJeoDG3hYHiJJy8s+ZUEq8IXgQoVUxwnKSzkj/BTn6BqjoPJKNwLSJahgeQzg
k4xgI5pawkt25N4h6oIgoAKE5qxRwO8yF6lF0R52TdRC8k5kWc1Fn2NAjySI5odUZ1jOZ32mhmBQ
IYDElmdeTlAtAUpYHIRqHHylDz952UQpJ+9YUOODTDBfFnRNB945YGjyqm41xJiYDWx4uNvuJ2GH
NSvyxg5qieB0KQY3LHQdEldXCqCiFBBA0hUGumABkAPmmA5CdBKJZEpwvCORQr9IfSkUYUgVaj42
TjowKAhtZ8G08JTIWstBKhbqiOq0kmCu1PdA0H04ozzfOcHQXMnQJZC6RkGKySsS7JKXu5IWlyZQ
jjLFKok7qT+Kpj3SjoqDfTWuiDsQFt8VuSAuwUjBFakMSajMA5msk0KpCnkqvFkEeMWuy2Rvtt98
RU36qD6SBCoXjYBaKk0GfZlDTKmqOxwRNyNQrqrowFOJBjBUEyFYxL1SXNzEgcqWFzkCKrpEEhqU
qqWSilYFAZBXwVYgCb264rKMhFSmRUk9glmc8vq1Y9HXwYvgZblFOQROUEcqJJG+wKFLRZVoxEIq
q6haqxRGnivFQRJIUSSxhLxtRpLI/UYyInqek5F0kCgCHx7BkJurf49b8y/zPy9X6C9X6C9X6C9X
6C9X6P+3K/THD4/EuNvj8XBcvdrf39w8Pv4BzNA98AMjAAA=
headers:
Age:
- '0'
- '1'
Connection:
- keep-alive
Expect-CT:
Expand All @@ -56,6 +71,8 @@ interactions:
- no-referrer-when-downgrade
Strict-Transport-Security:
- max-age=15552000
Transfer-Encoding:
- chunked
X-Content-Type-Options:
- nosniff
X-Frame-Options:
Expand All @@ -66,26 +83,24 @@ interactions:
- public, max-age=10, stale-while-revalidate=20
content-encoding:
- gzip
content-length:
- '1773'
content-type:
- application/json;charset=utf-8
date:
- Tue, 22 Feb 2022 08:08:54 GMT
- Tue, 12 Apr 2022 11:42:23 GMT
server:
- ATS
vary:
- Origin,Accept-Encoding
x-envoy-decorator-operation:
- finance-chart-api--mtls-production-ir2.finance-k8s.svc.yahoo.local:4080/*
- finance-chart-api--mtls-production-sg3.finance-k8s.svc.yahoo.local:4080/*
x-envoy-upstream-service-time:
- '4'
- '3'
x-request-id:
- 06ea0e14-2d52-4652-86a5-2974a504a71c
- 2f74a9a5-aa72-482e-97b4-79b037631670
x-yahoo-request-id:
- 7smvs8dh196gm
- 4odqgb9h5apd0
y-rid:
- 7smvs8dh196gm
- 4odqgb9h5apd0
status:
code: 200
message: OK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

[Yahoo Finance]
shorted show most shorted stocks
[Interactive Broker]
ctb stocks with highest cost to borrow
[Shortinterest.com]
hsi show top high short interest stocks of over 20% ratio
[FINRA]
Expand Down
62 changes: 62 additions & 0 deletions website/content/terminal/stocks/dark_pool_shorts/ctb/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
```
usage: ctb [-n NUM] [--export {csv,json,xlsx}] [-h]
```

Request a list of stocks that have the highest cost to borrow [Source: Interactive Broker]

```
optional arguments:
-n NUM, --num NUM Number of the stocks with high cost to borrow to retrieve. (default: 20)
--export {csv,json,xlsx}
Export dataframe data to csv,json,xlsx file
-h, --help show this help message (default: False)
```

Example:
```
2022 Apr 07, 09:47 (�) /stocks/dps/ $ ctb
Highest Cost to Borrow
┌─────────┬───────────┬───────────┐
│ Symbol │ Fees │ Available │
├─────────┼───────────┼───────────┤
│ PIK │ 457.4402% │ 7000 │
├─────────┼───────────┼───────────┤
│ EVTL │ 413.7294% │ 10000 │
├─────────┼───────────┼───────────┤
│ CELZ │ 330.9411% │ 100000 │
├─────────┼───────────┼───────────┤
│ DRCT │ 304.9628% │ 300000 │
├─────────┼───────────┼───────────┤
│ MYNZ │ 291.8163% │ 3000 │
├─────────┼───────────┼───────────┤
│ DCFC │ 279.0673% │ 10000 │
├─────────┼───────────┼───────────┤
│ FGFPP │ 278.422% │ 8000 │
├─────────┼───────────┼───────────┤
│ ZTEK │ 250.0307% │ 75000 │
├─────────┼───────────┼───────────┤
│ FRGE │ 245.1883% │ 700 │
├─────────┼───────────┼───────────┤
│ SATL │ 240.7341% │ 500 │
├─────────┼───────────┼───────────┤
│ ARMR │ 240.5414% │ 5000 │
├─────────┼───────────┼───────────┤
│ PILL │ 223.538% │ 55000 │
├─────────┼───────────┼───────────┤
│ ARQQ │ 217.3978% │ 3000 │
├─────────┼───────────┼───────────┤
│ NRSN │ 216.9888% │ 6000 │
├─────────┼───────────┼───────────┤
│ ZIONL │ 215.2871% │ 35000 │
├─────────┼───────────┼───────────┤
│ BLBX │ 213.441% │ 15000 │
├─────────┼───────────┼───────────┤
│ WINSF │ 212.907% │ 10000 │
├─────────┼───────────┼───────────┤
│ SKYH │ 206.7746% │ 25000 │
├─────────┼───────────┼───────────┤
│ SOHON │ 205.1096% │ 40000 │
├─────────┼───────────┼───────────┤
│ MH PRA │ 202.1235% │ 100000 │
└─────────┴───────────┴───────────┘
```
2 changes: 2 additions & 0 deletions website/data/menu/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ main:
sub:
- name: shorted
ref: "/terminal/stocks/dark_pool_shorts/shorted"
- name: ctb
ref: "/terminal/stocks/dark_pool_shorts/ctb"
- name: hsi
ref: "/terminal/stocks/dark_pool_shorts/hsi"
- name: prom
Expand Down

0 comments on commit 73187d9

Please sign in to comment.