Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ jobs:
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- uses: actions/setup-python@v2
with:
python-version: 3.7
python-version: 3.10
- name: Run image
uses: abatilo/[email protected]
with:
poetry-version: 1.3.2
poetry-version: 1.7.1
- name: Publish python package
run: poetry version ${{ steps.vars.outputs.tag }} && poetry config pypi-token.pypi ${{ secrets.PYPI_API_KEY }} && poetry build && poetry publish
- name: Auto commit pyproject.toml
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
poetry-version: [1.3.2]
python-version: ["3.10", "3.11", "3.12", "3.13"]
poetry-version: [1.7.1]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -29,18 +29,18 @@ jobs:
run: poetry install && poetry run pytest --cov=stake --cov-report=xml && poetry run coverage-badge -f -o coverage.svg
- name: Upload coverage
uses: actions/upload-artifact@v2
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.7 }}
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.10 }}
with:
name: coverage
path: coverage.svg
- name: Auto commit coverage badge
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.7 }}
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.10 }}
uses: EndBug/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@master
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.7 }}
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 3.10 }}
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: coverage.xml
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,5 @@ STAKE.*.json
.idea
DS_Store
.DS_Store

.idx/
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
repos:
- repo: "https://github.com/pre-commit/pre-commit-hooks"
rev: v4.3.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: requirements-txt-fixer
- repo: "https://github.com/psf/black"
rev: 22.6.0
rev: 25.1.0
hooks:
- id: black
- repo: "https://github.com/pre-commit/mirrors-mypy"
rev: v0.961
rev: v1.16.1
hooks:
- id: mypy
- repo: "https://github.com/PyCQA/isort"
rev: 5.12.0
rev: 6.0.1
hooks:
- id: isort
- repo: "https://github.com/asottile/seed-isort-config"
rev: v2.2.0
hooks:
- id: seed-isort-config
- repo: "https://github.com/myint/docformatter"
rev: v1.4
rev: v1.7.7
hooks:
- id: docformatter
args:
- "--in-place"
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: "v0.0.254"
rev: "v0.12.2"
hooks:
- id: ruff
- repo: https://github.com/pre-commit/mirrors-prettier
Expand Down
2,341 changes: 1,358 additions & 983 deletions poetry.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,31 @@ license = "Apache-2.0"
keywords = ["stake","trading","stocks","financial","python"]

[tool.poetry.dependencies]
python = ">=3.8,<4.0.0"
python = ">=3.10,<4.0.0"
python-dotenv = "^0.13.0"
pydantic = "^2.3"
inflection = "^0.5.0"
aiohttp = "^3.9"
single-version = "^1.2.2"

[tool.poetry.dev-dependencies]
pytest = "^7.2.0"
pytest-asyncio = "^0.14.0"
pytest = "^8.4.1"
pytest-asyncio = "^1.0.0"
pre-commit-hooks = "^3.1.0"
pre-commit = "^2.12.0"
pre-commit = "^4.2.0"
pytest-coverage = "^0.0"
black = {version = "^19.10b0", allow-prereleases = true}
pytest-mock = "^3.3.0"
faker = "^4.14.0"
coverage-badge = "^1.0.1"
pytest-recording = "^0.12.0"
pytest-recording = "^0.13.4"

[tool.poetry.group.dev.dependencies]
bump-pydantic = "^0.8.0"

[tool.isort]
profile = "black"
known_third_party = ["aiohttp", "dotenv", "faker", "inflection", "pydantic", "pytest", "single_version"]
known_third_party = ["aiohttp", "dotenv", "faker", "inflection", "pydantic", "pytest", "pytest_asyncio", "single_version"]
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
Expand Down
1 change: 1 addition & 0 deletions stake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .order import * # noqa: F401, F403
from .product import * # noqa: F401, F403
from .ratings import * # noqa: F401, F403
from .statement import * # noqa: F401, F403
from .trade import * # noqa: F401, F403
from .transaction import * # noqa: F401, F403
from .watchlist import * # noqa: F401, F403
Expand Down
4 changes: 2 additions & 2 deletions stake/asx/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class Side(str, Enum):
class TradeType(str, Enum):
"""The type of trade the user is requesting."""

MARKET: str = "MARKET_TO_LIMIT"
LIMIT: str = "LIMIT"
MARKET = "MARKET_TO_LIMIT"
LIMIT = "LIMIT"
11 changes: 7 additions & 4 deletions stake/asx/market.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import date
from datetime import datetime
from typing import Optional

import pydantic
Expand All @@ -10,11 +10,11 @@


class Status(pydantic.BaseModel):
current: Optional[str] = None
current: str


class MarketStatus(pydantic.BaseModel):
last_trading_date: Optional[date] = None
last_trading_date: Optional[datetime] = None
status: Status
model_config = ConfigDict(alias_generator=camelcase)

Expand All @@ -24,7 +24,10 @@ class MarketClient(BaseClient):

async def get(self) -> MarketStatus:
data = await self._client.get(self._client.exchange.market_status)
return MarketStatus(**data)
return MarketStatus(
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Directly indexing data[0] assumes a non-empty list response.

This could raise an IndexError if the list is empty. Please add a check to handle empty responses.

last_trading_date=data[0]["lastTradedTimestamp"],
status=Status(current=data[0]["marketStatus"]),
)

async def is_open(self) -> bool:
status = await self.get()
Expand Down
4 changes: 2 additions & 2 deletions stake/asx/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
class ExpiryDate(str, Enum):
"""The expiry date for the trade."""

IN_ONE_DAY: str = "GFD"
IN_THIRTY_DAYS: str = "GTC"
IN_ONE_DAY = "GFD"
IN_THIRTY_DAYS = "GTC"


class GenericTradeRequest(BaseModel):
Expand Down
4 changes: 2 additions & 2 deletions stake/asx/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@


class SortDirection(str, Enum):
ASC: str = "asc"
DESC: str = "desc"
ASC = "asc"
DESC = "desc"


class Sort(BaseModel):
Expand Down
55 changes: 31 additions & 24 deletions stake/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
order,
product,
ratings,
statement,
trade,
transaction,
user,
Expand Down Expand Up @@ -70,7 +71,9 @@ def url(endpoint: str) -> str:
return endpoint

@staticmethod
async def get(url: str, payload: dict = None, headers: dict = None) -> dict:
async def get(
url: str, payload: dict | None = None, headers: dict | None = None
) -> dict:
async with aiohttp.ClientSession(
headers=headers, raise_for_status=True
) as session:
Expand All @@ -80,7 +83,7 @@ async def get(url: str, payload: dict = None, headers: dict = None) -> dict:
return await response.json()

@staticmethod
async def post(url: str, payload: dict, headers: dict = None) -> dict:
async def post(url: str, payload: dict, headers: dict | None = None) -> dict:

async with aiohttp.ClientSession(
headers=headers, raise_for_status=True
Expand All @@ -92,7 +95,9 @@ async def post(url: str, payload: dict, headers: dict = None) -> dict:
return await response.json()

@staticmethod
async def delete(url: str, payload: dict = None, headers: dict = None) -> dict:
async def delete(
url: str, payload: dict | None = None, headers: dict | None = None
) -> dict:
async with aiohttp.ClientSession(
headers=headers, raise_for_status=True
) as session:
Expand All @@ -111,7 +116,7 @@ class StakeClient:

def __init__(
self,
request: Union[CredentialsLoginRequest, SessionTokenLoginRequest] = None,
request: Union[CredentialsLoginRequest, SessionTokenLoginRequest, None] = None,
exchange: Union[constant.NYSEUrl, constant.ASXUrl] = constant.NYSE,
):
"""
Expand All @@ -137,28 +142,29 @@ def set_exchange(self, exchange: Union[constant.NYSEUrl, constant.ASXUrl]) -> No
self.watchlist: watchlist.WatchlistClient = watchlist.WatchlistClient(self)

if exchange == constant.ASX:
self.equities: Union[
asx.equity.EquitiesClient, equity.EquitiesClient
] = asx.equity.EquitiesClient(self)
self.fundings: Union[
asx.funding.FundingsClient, funding.FundingsClient
] = asx.funding.FundingsClient(self)
self.market: Union[
asx.market.MarketClient, market.MarketClient
] = asx.market.MarketClient(self)
self.orders: Union[
asx.order.OrdersClient, order.OrdersClient
] = asx.order.OrdersClient(self)
self.products: Union[
asx.product.ProductsClient, product.ProductsClient
] = asx.product.ProductsClient(self)
self.trades: Union[
asx.trade.TradesClient, trade.TradesClient
] = asx.trade.TradesClient(self)
self.equities: Union[asx.equity.EquitiesClient, equity.EquitiesClient] = (
Copy link

Choose a reason for hiding this comment

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

issue (code-quality): Extract code out into method [×2] (extract-method)

asx.equity.EquitiesClient(self)
)
self.fundings: Union[asx.funding.FundingsClient, funding.FundingsClient] = (
asx.funding.FundingsClient(self)
)
self.market: Union[asx.market.MarketClient, market.MarketClient] = (
asx.market.MarketClient(self)
)
self.orders: Union[asx.order.OrdersClient, order.OrdersClient] = (
asx.order.OrdersClient(self)
)
self.products: Union[asx.product.ProductsClient, product.ProductsClient] = (
asx.product.ProductsClient(self)
)
self.trades: Union[asx.trade.TradesClient, trade.TradesClient] = (
asx.trade.TradesClient(self)
)
self.transactions: Union[
asx.transaction.TransactionsClient, transaction.TransactionsClient
] = asx.transaction.TransactionsClient(self)
# ratings is unsupported.
# statements is unsupported.
else:
self.equities = equity.EquitiesClient(self)
self.fundings = funding.FundingsClient(self)
Expand All @@ -169,8 +175,9 @@ def set_exchange(self, exchange: Union[constant.NYSEUrl, constant.ASXUrl]) -> No
self.ratings = ratings.RatingsClient(self)
self.trades = trade.TradesClient(self)
self.transactions = transaction.TransactionsClient(self)
self.statements = statement.StatementClient(self)

async def get(self, url: str, payload: dict = None) -> dict:
async def get(self, url: str, payload: dict | None = None) -> dict:
"""Performs an HTTP get operation.

Args:
Expand Down Expand Up @@ -200,7 +207,7 @@ async def post(self, url: str, payload: dict) -> dict:
url, payload=payload, headers=self.headers.model_dump(by_alias=True)
)

async def delete(self, url: str, payload: dict = None) -> dict:
async def delete(self, url: str, payload: dict | None = None) -> dict:
"""Performs an HTTP delete operation.

Args:
Expand Down
10 changes: 9 additions & 1 deletion stake/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ class NYSEUrl(BaseModel):
)
update_watchlist: str = read_watchlist + "/items"

statement: str = urljoin(
STAKE_URL,
"data/fundamentals/{symbol}/statements?startDate={date}",
allow_fragments=True,
)


NYSE = NYSEUrl()

Expand All @@ -107,7 +113,9 @@ class ASXUrl(BaseModel):
equity_positions: str = urljoin(
ASX_STAKE_URL, "instrument/equityPositions", allow_fragments=True
)
market_status: str = "https://early-bird-promo.hellostake.com/marketStatus"
market_status: str = urljoin(
ASX_STAKE_URL, "instrument/quoteTwo/ASX", allow_fragments=True
)

orders: str = urljoin(ASX_STAKE_URL, "orders", allow_fragments=True)

Expand Down
5 changes: 3 additions & 2 deletions stake/fx.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Currency conversion."""

from enum import Enum

from pydantic import BaseModel, ConfigDict
Expand All @@ -10,8 +11,8 @@


class CurrencyEnum(str, Enum):
AUD: str = "AUD"
USD: str = "USD"
AUD = "AUD"
USD = "USD"


class FxConversionRequest(BaseModel):
Expand Down
1 change: 0 additions & 1 deletion stake/ratings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,4 @@ async def list(self, request: RatingsRequest) -> List[Rating]:

if data == {"message": "No data returned"}:
return []
print(data["ratings"])
return [Rating(**d) for d in data["ratings"]]
Loading
Loading