Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redo Screener #2190

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft

Redo Screener #2190

wants to merge 5 commits into from

Conversation

R5dan
Copy link
Contributor

@R5dan R5dan commented Dec 23, 2024

It is annoying that the types are wrong on Screener, I find myself looking at the source code to determine the types of the Screener class so this is a fix

@ericpien
Copy link
Contributor

  1. what do you mean the "types are wrong"?
  2. What does it mean to "determine the types of the Screener class"?
  3. How can we improve the documentation for Screener to avoid "looking at the source code"?

@R5dan
Copy link
Contributor Author

R5dan commented Dec 24, 2024

1. what do you mean the "types are wrong"?

The return types on the Screener are wrong (for example dict not dict_keys on predefined_bodies which seems trivial but the methods are different on them) etc

2. What does it mean to "determine the types of the Screener class"?

I go into the source code to work out what types different properties are as when I run code (which would be correct with the types) it fails (due to incorrect type)

I also have to go looking for what string literals are allowed in set_predefined_body when they are hard coded in and most type checkers can prompt you to which ones to use.

3. How can we improve the documentation for Screener to avoid "looking at the source code"?

Mostly fixed it with this PR. Take a look if you want.

I also made the the types run faster and be more runtime safe: by putting the type in a string it only has to construct a string and not the full class and it also means it's easier to fix circular import errors or the class not actually existing for some reason as some of them could be moved under t.TYPE_CHECKING if needed

@R5dan
Copy link
Contributor Author

R5dan commented Dec 30, 2024

@ValueRaider What do you think?

@ValueRaider
Copy link
Collaborator

How can we improve the documentation for Screener

Improve how user sets up a screener query with a simpler intermediate form:

from dataclasses import dataclass
from typing import List, Union, Any

@dataclass
class Query:
    operator: str
    operands: List[Union['Query', Any]]

    def to_dict(self) -> dict:
        return {
            "operator": self.operator,
            "operands": [op.to_dict() if isinstance(op, Query) else op 
                         for op in self.operands]}

def value_in(key: str, *values):
   return Query("or", [Query("eq", [key, v]) for v in values])

query = Query(
    "and",
    [
        value_in("exchange", "NMS", "NYQ"),
        Query("lt", ["epsgrowth.lasttwelvemonths", 15])
    ]
)

Should shorten the screener html page by a lot.

@R5dan
Copy link
Contributor Author

R5dan commented Dec 30, 2024

Should I also add #154 into this one?

@ValueRaider
Copy link
Collaborator

ok

@R5dan
Copy link
Contributor Author

R5dan commented Dec 30, 2024

@ValueRaider any other predefined keys you know off? Still don't know where you found that 52 week gain

@R5dan
Copy link
Contributor Author

R5dan commented Dec 30, 2024

Also why is Query and EquityQuery different? EquityQuery doesn't even have region etc.

@R5dan R5dan marked this pull request as draft December 31, 2024 09:33
@ValueRaider
Copy link
Collaborator

ValueRaider commented Dec 31, 2024

@ValueRaider any other predefined keys you know off? Still don't know where you found that 52 week gain

I just navigated the gainers webpage with Firefox network inspector open.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 1, 2025

@ValueRaider Still need to add proper logging (not just print statements) and docs etc, but what do you think of this.
I am getting the error:

{
    "finance":
        {
            "result":null,
            "error":
                {
                    "code":"internal-error",
                    "description":"sort field is not a field: fundnetassets"
                }
         }
}

returned by yahoo. I don't understand why as this part is the same as the original and that works fine. Any ideas?

@R5dan R5dan changed the title Update user types for Screener Redo Screener Jan 1, 2025
self._body_updated = True
self._body = body
return self

def patch_body(self, values: Dict) -> 'Screener':

def patch_body(self, offset: 'int' = 0, size: 'int' = 100, sortField: 'str' = "ticker", sortType: 'str' = "desc", quoteType: 'str' = "equity", userId: 'str' = "", userIdType: 'str' = "guid"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't this result in unintentional updates of certain fields?

i.e. user with body offset = 50, goes to patch the sortField but offset will reset to 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it would, except it is not implemented yet. Will change it when I do implement it

fetch and parse the screener results, and access predefined screener bodies.
"""
def __init__(self, session=None, proxy=None):
class PredefinedScreener:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need a separate class for this? Isn't this just a Screener with pre-defined fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it sends a different request to a different endpoint with a different response

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you access the yahoo's screener via: https://finance.yahoo.com/research-hub/screener, the request is made to the same endpoint for the pre-defined queries.

imho, it's better to not create a separate class for this to allow user to construct a Screener that reflects the pre-defined body, and edit it as they need for flexibility. i.e. offset, or exchange requirements.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 1, 2025

Sure but:

AttributeError: module 'yfinance' has no attribute 'screener'

Weird, I don't get that error:

from yfinance.screener import Screener

predefined = Screener.predefined("day_gainers", count=25)

@ericpien
Copy link
Contributor

ericpien commented Jan 1, 2025

Below are just my two cents:

I think this affects more than just types as initially proposed and there isn't much example/test code to infer. Can you edit the tests for the changes to assist in code review?

I'm actually not sure what problem this PR is trying to solve anymore.

Also why is Query and EquityQuery different? EquityQuery doesn't even have region etc.

This was done so future developers can extend to different types of queries but leverage the same screener class. i.e. quoteType = "MUTUALFUND"

I also made the the types run faster and be more runtime safe: by putting the type in a string it only has to construct a string and not the full class and it also means it's easier to fix circular import errors or the class not actually existing for some reason as some of them could be moved under t.TYPE_CHECKING if needed

I personally have a preference for using the typing module instead for readability and maintainability.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 1, 2025

It was initially just to edit the Types but then I was asked to fix the Query and EntityQuery and make screener better and easier. I understand what you are saying about having no direction, it is now to redo the screener to make it easier to use and make custom queries etc.

I personally have a preference for using the typing module instead for readability and maintainability.

Personally I generally prefer as little from typing as possible (except certain things)

there isn't much example/test code to infer

Yes, I am going to add more, just wanted to see whether people like this, or want specific and overall changes before implementing more specific, adding docs and tests, I just wanted to get something working. This is a draft pr so far.

Repository owner deleted a comment from R5dan Jan 2, 2025
Repository owner deleted a comment from R5dan Jan 2, 2025
Repository owner deleted a comment from R5dan Jan 2, 2025
Repository owner deleted a comment from R5dan Jan 2, 2025
@ValueRaider
Copy link
Collaborator

ValueRaider commented Jan 2, 2025

Ok, I have your code running now. I've deleted those comments to tidy this thread and get back on track.

I'm actually not sure what problem this PR is trying to solve anymore.

Might be my fault. I only just now understand that @ericpien implemented a Query class that appears to do what I wanted. I need to spend more time with the existing screener and query, simplify the docs.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 3, 2025

Might be my fault. I only just now understand that @ericpien implemented a Query class that appears to do what I wanted.

Do you want me to stop this then?

@ValueRaider
Copy link
Collaborator

Do you want me to stop this then?

Pause for now. I'll look more over weekend.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 5, 2025

@ValueRaider Made a decision? Are you just going to go with #2207

@ValueRaider
Copy link
Collaborator

@R5dan relax, let's work through #2207 then after see where this PR fits in.

@R5dan
Copy link
Contributor Author

R5dan commented Jan 5, 2025

I was just checking. Wanted to see if you wanted me to continue or not, so Ill pause for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants