Exemple #1
0
def test_option_expirations_invalid_status(mocker):
    mock_response = requests.Response()
    mock_response.status_code = 400
    mocker.patch(target="requests.get", new=mocker.Mock(return_value=mock_response))

    result_list = tradier_model.option_expirations(ticker="PM")

    assert result_list == []
Exemple #2
0
def test_option_expirations_json_error(mocker):
    mock_response = requests.Response()
    mock_response.status_code = 200
    mocker.patch.object(
        target=mock_response,
        attribute="json",
        side_effect=TypeError(),
    )
    mocker.patch(target="requests.get", new=mocker.Mock(return_value=mock_response))

    result_list = tradier_model.option_expirations(ticker="PM")

    assert result_list == []
Exemple #3
0
    def __init__(self, ticker: str, queue: List[str] = None):
        """Constructor"""
        super().__init__(queue)

        self.ticker = ticker
        self.prices = pd.DataFrame(columns=["Price", "Chance"])
        self.selected_date = ""
        self.chain = None

        if ticker:
            if TRADIER_TOKEN == "REPLACE_ME":  # nosec
                console.print("Loaded expiry dates from Yahoo Finance")
                self.expiry_dates = yfinance_model.option_expirations(
                    self.ticker)
            else:
                console.print("Loaded expiry dates from Tradier")
                self.expiry_dates = tradier_model.option_expirations(
                    self.ticker)
        else:
            self.expiry_dates = []

        if session and gtff.USE_PROMPT_TOOLKIT:
            choices: dict = {c: {} for c in self.controller_choices}
            choices["unu"]["-s"] = {c: {} for c in self.unu_sortby_choices}
            choices["pcr"] = {c: {} for c in self.pcr_length_choices}
            choices["disp"] = {c: {} for c in self.presets}
            choices["scr"] = {c: {} for c in self.presets}
            choices["grhist"]["-g"] = {
                c: {}
                for c in self.grhist_greeks_choices
            }
            choices["load"]["-s"] = {c: {} for c in self.load_source_choices}
            choices["load"]["--source"] = {
                c: {}
                for c in self.hist_source_choices
            }
            choices["load"]["-s"] = {c: {} for c in self.voi_source_choices}
            choices["plot"]["-x"] = {c: {} for c in self.plot_vars_choices}
            choices["plot"]["-y"] = {c: {} for c in self.plot_vars_choices}
            choices["plot"]["-c"] = {c: {} for c in self.plot_custom_choices}
            # This menu contains dynamic choices that may change during runtime
            self.choices = choices
            self.completer = NestedCompleter.from_nested_dict(choices)
Exemple #4
0
    def call_load(self, other_args: List[str]):
        """Process load command"""
        parser = argparse.ArgumentParser(
            add_help=False,
            formatter_class=argparse.ArgumentDefaultsHelpFormatter,
            prog="load",
            description="Load a ticker into option menu",
        )
        parser.add_argument(
            "-t",
            "--ticker",
            action="store",
            dest="ticker",
            required="-h" not in other_args,
            help="Stock ticker",
        )
        parser.add_argument(
            "-s",
            "--source",
            choices=self.load_source_choices,
            dest="source",
            default=None,
            help="Source to get option expirations from",
        )
        if other_args and "-" not in other_args[0][0]:
            other_args.insert(0, "-t")
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if ns_parser:
            self.ticker = ns_parser.ticker.upper()
            self.update_runtime_choices()

            if TRADIER_TOKEN == "REPLACE_ME" or ns_parser.source == "yf":  # nosec
                self.expiry_dates = yfinance_model.option_expirations(
                    self.ticker)
            else:
                self.expiry_dates = tradier_model.option_expirations(
                    self.ticker)
            console.print("")

            if self.ticker and self.selected_date:
                self.chain = yfinance_model.get_option_chain(
                    self.ticker, self.selected_date)
Exemple #5
0
def test_option_expirations(recorder):
    result_list = tradier_model.option_expirations(ticker="AAPL")
    recorder.capture(result_list)
    def __init__(self, ticker: str, queue: List[str] = None):
        """Constructor"""
        self.op_parser = argparse.ArgumentParser(add_help=False, prog="op")
        self.op_parser.add_argument(
            "cmd",
            choices=self.CHOICES,
        )

        self.completer: Union[None, NestedCompleter] = None

        if session and gtff.USE_PROMPT_TOOLKIT:

            self.choices: dict = {c: {} for c in self.CHOICES}
            self.choices["unu"]["-s"] = {
                c: {}
                for c in self.unu_sortby_choices
            }
            self.choices["pcr"] = {c: {} for c in self.pcr_length_choices}
            self.choices["disp"] = {c: {} for c in self.presets}
            self.choices["scr"] = {c: {} for c in self.presets}
            self.choices["grhist"]["-g"] = {
                c: {}
                for c in self.grhist_greeks_choices
            }
            self.choices["load"]["-s"] = {
                c: {}
                for c in self.load_source_choices
            }
            self.choices["load"]["--source"] = {
                c: {}
                for c in self.hist_source_choices
            }
            self.choices["load"]["-s"] = {
                c: {}
                for c in self.voi_source_choices
            }
            self.choices["plot"]["-x"] = {
                c: {}
                for c in self.plot_vars_choices
            }
            self.choices["plot"]["-y"] = {
                c: {}
                for c in self.plot_vars_choices
            }
            self.choices["plot"]["-c"] = {
                c: {}
                for c in self.plot_custom_choices
            }

        self.ticker = ticker
        self.prices = pd.DataFrame(columns=["Price", "Chance"])
        self.selected_date = ""
        self.chain = None

        if ticker:
            if TRADIER_TOKEN == "REPLACE_ME":
                print("Loaded expiry dates from Yahoo Finance")
                self.expiry_dates = yfinance_model.option_expirations(
                    self.ticker)
            else:
                print("Loaded expiry dates from Tradier")
                self.expiry_dates = tradier_model.option_expirations(
                    self.ticker)
        else:
            self.expiry_dates = []

        if queue:
            self.queue = queue
        else:
            self.queue = list()
    async def opt(
        self,
        ctx: discord.ext.commands.Context,
        ticker="",
        expiration="",
        strike="",
        put="",
    ):
        """Stocks Context - Shows Options Menu

        Run `!help OptionsCommands` to see the list of available commands.

        Returns
        -------
        Sends a message to the discord user with the commands from the stocks/options context.
        The user can then select a reaction to trigger a command.
        """
        logger.info("!stocks.opt %s %s %s %s", ticker, expiration, strike, put)
        async with ctx.typing():
            await asyncio.sleep(0.2)

            if TRADIER_TOKEN == "REPLACE_ME":  # nosec
                dates = yfinance_model.option_expirations(ticker)
            else:
                dates = tradier_model.option_expirations(ticker)

            index_dates = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

            if not ticker:
                current = 0
                text = (
                    "```0️⃣ !stocks.opt.unu```\n"
                    "Provide a ticker and expiration date with this menu,\n"
                    "\ne.g.\n!stocks.opt TSLA 0-9\n!stocks.opt TSLA 2021-06-04"
                )

            if (ticker != "") and (expiration == ""):
                current = 1
                text = ("```0️⃣ !stocks.opt.unu\n"
                        f"1️⃣ !stocks.opt.exp {ticker}\n"
                        f"2️⃣ !stocks.opt.iv {ticker}\n```")

            if expiration:
                current = 2
                exp = int(expiration.replace("-", ""))
                if exp > 9 and (expiration
                                not in dates) and (exp not in index_dates):
                    call_arg = (strike, put)
                    func_cmd = opt_command
                    expiry = None
                    await expiry_dates_reaction(ctx, ticker, expiry, func_cmd,
                                                call_arg)
                    return
                if exp in index_dates:
                    expiration = dates[int(expiration)]

                hist = f"7️⃣ !stocks.opt.hist {ticker} (strike*) (c/p*) {expiration}\n\n* Required"
                if strike and put:
                    hist = f"7️⃣ !stocks.opt.hist {ticker} {strike} {put} {expiration}"
                    current = 3

                text = ("```0️⃣ !stocks.opt.unu\n"
                        f"1️⃣ !stocks.opt.exp {ticker}\n"
                        f"2️⃣ !stocks.opt.iv {ticker}\n"
                        f"3️⃣ !stocks.opt.calls {ticker} {expiration} \n"
                        f"4️⃣ !stocks.opt.puts {ticker} {expiration} \n"
                        f"5️⃣ !stocks.opt.oi {ticker} {expiration} \n"
                        f"6️⃣ !stocks.opt.vol {ticker} {expiration} \n"
                        f"{hist}```")

            if put == "p":
                put = bool(True)
            if put == "c":
                put = bool(False)

            title = "Stocks: Options Menu"
            embed = discord.Embed(title=title,
                                  description=text,
                                  colour=cfg.COLOR)
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            msg = await ctx.send(embed=embed, delete_after=60.0)

            if current == 0:
                emoji_list = ["0️⃣"]
            if current == 1:
                emoji_list = ["0️⃣", "1️⃣", "2️⃣"]
            if current == 2:
                emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣"]
            if current == 3:
                emoji_list = [
                    "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"
                ]

            for emoji in emoji_list:
                await msg.add_reaction(emoji)

            def check(reaction, user):
                return user == ctx.message.author and str(
                    reaction.emoji) in emoji_list

            try:
                reaction, _ = await gst_bot.wait_for("reaction_add",
                                                     timeout=cfg.MENU_TIMEOUT,
                                                     check=check)
                if reaction.emoji == "0️⃣":
                    logger.info("Reaction selected: 0")
                    await unu_command(ctx)
                elif reaction.emoji == "1️⃣":
                    logger.info("Reaction selected: 1")
                    await expirations_command(ctx, ticker)
                elif reaction.emoji == "2️⃣":
                    logger.info("Reaction selected: 2")
                    await iv_command(ctx, ticker)
                elif reaction.emoji == "3️⃣":
                    logger.info("Reaction selected: 3")
                    await calls_command(ctx, ticker, expiration)
                elif reaction.emoji == "4️⃣":
                    logger.info("Reaction selected: 4")
                    await puts_command(ctx, ticker, expiration)
                elif reaction.emoji == "5️⃣":
                    logger.info("Reaction selected: 5")
                    await oi_command(ctx, ticker, expiration)
                elif reaction.emoji == "6️⃣":
                    logger.info("Reaction selected: 6")
                    await vol_command(ctx, ticker, expiration)
                elif reaction.emoji == "7️⃣":
                    logger.info("Reaction selected: 7")
                    strike = float(strike)
                    await hist_command(ctx, ticker, expiration, strike, put)

                for emoji in emoji_list:
                    await msg.remove_reaction(emoji, ctx.bot.user)

            except asyncio.TimeoutError:
                for emoji in emoji_list:
                    await msg.remove_reaction(emoji, ctx.bot.user)
                if cfg.DEBUG:
                    embed = discord.Embed(
                        description="Error timeout - you snooze you lose! 😋",
                        colour=cfg.COLOR,
                        title="TIMEOUT Stocks: Options Menu",
                    ).set_author(
                        name=cfg.AUTHOR_NAME,
                        icon_url=cfg.AUTHOR_ICON_URL,
                    )
                    await ctx.send(embed=embed, delete_after=30.0)
async def expiry_dates_reaction(ctx,
                                ticker,
                                expiry,
                                func_cmd,
                                call_arg: tuple = None):
    if TRADIER_TOKEN == "REPLACE_ME":  # nosec
        dates = yfinance_model.option_expirations(ticker)
    else:
        dates = tradier_model.option_expirations(ticker)

    index_dates = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    if expiry is not None:
        try:
            if expiry not in dates:
                exp = int(expiry.replace("-", ""))

            if (expiry not in dates) and (exp not in index_dates):
                raise Exception("Enter a valid expiration date.")

            if expiry in dates:
                if call_arg is None:
                    await func_cmd(ctx, ticker, expiry)
                else:
                    await func_cmd(ctx, ticker, expiry, *call_arg)
                return
            if exp in index_dates:
                expiry = dates[int(expiry)]
                if call_arg is None:
                    await func_cmd(ctx, ticker, expiry)
                else:
                    await func_cmd(ctx, ticker, expiry, *call_arg)
                return

        except Exception as e:
            embed = discord.Embed(
                title="ERROR Options: Expiry Date",
                colour=cfg.COLOR,
                description=e,
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            await ctx.send(embed=embed, delete_after=10.0)
            return

    if not dates:
        embed = discord.Embed(
            title="ERROR Options",
            colour=cfg.COLOR,
            description="Enter a valid stock ticker",
        )
        embed.set_author(
            name=cfg.AUTHOR_NAME,
            icon_url=cfg.AUTHOR_ICON_URL,
        )

        await ctx.send(embed=embed, delete_after=10.0)
        return

    text = ("```0️⃣ " + dates[0] + "\n"
            "1️⃣ " + dates[1] + "\n"
            "2️⃣ " + dates[2] + "\n"
            "3️⃣ " + dates[3] + "\n"
            "4️⃣ " + dates[4] + "\n"
            "5️⃣ " + dates[5] + "\n"
            "6️⃣ " + dates[6] + "\n"
            "7️⃣ " + dates[7] + "\n"
            "8️⃣ " + dates[8] + "\n"
            "9️⃣ " + dates[9] + "```")

    title = " " + ticker.upper() + " Options: Expiry Date"
    embed = discord.Embed(title=title, description=text, colour=cfg.COLOR)
    embed.set_author(
        name=cfg.AUTHOR_NAME,
        icon_url=cfg.AUTHOR_ICON_URL,
    )

    msg = await ctx.send(embed=embed, delete_after=15.0)

    emoji_list = [
        "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"
    ]

    for emoji in emoji_list:
        await msg.add_reaction(emoji)

    def check(reaction, user):
        return user == ctx.message.author and str(reaction.emoji) in emoji_list

    try:
        reaction, _ = await gst_bot.wait_for("reaction_add",
                                             timeout=cfg.MENU_TIMEOUT,
                                             check=check)
        for N in range(0, 10):
            if reaction.emoji == emoji_list[N]:
                logger.info("Reaction selected: %d", N)
                expiry = dates[N]
                if call_arg is None:
                    await func_cmd(ctx, ticker, expiry)
                else:
                    await func_cmd(ctx, ticker, expiry, *call_arg)

        for emoji in emoji_list:
            await msg.remove_reaction(emoji, ctx.bot.user)

    except asyncio.TimeoutError:
        for emoji in emoji_list:
            await msg.remove_reaction(emoji, ctx.bot.user)
        if cfg.DEBUG:
            embed = discord.Embed(
                description="Error timeout - you snooze you lose! 😋",
                colour=cfg.COLOR,
                title="TIMEOUT  " + ticker.upper() + " Options: Expiry Date",
            )
            embed.set_author(
                name=cfg.AUTHOR_NAME,
                icon_url=cfg.AUTHOR_ICON_URL,
            )
            await ctx.send(embed=embed, delete_after=10.0)