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

test api call for order retrieval #16

Merged
merged 1 commit into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 42 additions & 1 deletion cschwabpy/SchwabAsyncClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@
OptionExpiration,
OptionExpirationChainResponse,
)
from cschwabpy.models.trade_models import AccountNumberModel, SecuritiesAccount, Account
from cschwabpy.models.trade_models import (
AccountNumberModel,
SecuritiesAccount,
Account,
OrderStatus,
Order,
)
import cschwabpy.util as util

from datetime import datetime, timedelta
from typing import Optional, List, Mapping
from cschwabpy.costants import (
SCHWAB_API_BASE_URL,
Expand Down Expand Up @@ -171,6 +180,38 @@ async def get_single_account_async(

return account[0]

async def get_orders_async(
self,
account_number: str,
from_entered_time: datetime,
to_entered_time: datetime,
max_count: int = 1000,
status: Optional[OrderStatus] = None,
) -> List[Order]:
await self._ensure_valid_access_token()
target_url = f"{SCHWAB_TRADER_API_BASE_URL}/accounts/{account_number}/orders"
target_url += f"?fromEnteredTime={util.to_iso8601_str(from_entered_time)}&toEnteredTime={util.to_iso8601_str(to_entered_time)}&maxResults={max_count}"
if status is not None:
target_url += f"&status={status.value}"

client = httpx.AsyncClient() if self.__client is None else self.__client
try:
response = await client.get(
url=target_url, params={}, headers=self.__auth_header()
)
if response.status_code == 200:
json_res = response.json()
orders: List[Order] = []
for order_json in json_res:
order = Order(**order_json)
orders.append(order)
return orders
else:
raise Exception("Failed to get orders. Status: ", response.status_code)
finally:
if not self.__keep_client_alive:
await client.aclose()

async def get_option_expirations_async(
self, underlying_symbol: str
) -> List[OptionExpiration]:
Expand Down
6 changes: 6 additions & 0 deletions cschwabpy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ def ts_to_date_string(
return ts_to_datetime(ts, tz).strftime(YMD_FMT)


def to_iso8601_str(dt: datetime) -> str:
dt = dt.astimezone(eastern_tz)
dt_str = dt.strftime("%Y-%m-%dT%H:%M:%S")
return dt_str + ".000Z"


def today_str(tz: pytz.BaseTzInfo = eastern_tz) -> str: # type: ignore
"""Today in string. Returns Y-m-d.""" # noqa: DAR201
return now(tz=tz).strftime(YMD_FMT)
34 changes: 34 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import typing
import httpx
import pytest
from datetime import datetime, timedelta
from pytest_httpx import HTTPXMock
from pathlib import Path
from cschwabpy.models import (
Expand All @@ -17,6 +18,7 @@
CashAccount,
AccountType,
Order,
OrderStatus,
)
from cschwabpy.models.token import Tokens, LocalTokenStore
from cschwabpy.SchwabAsyncClient import SchwabAsyncClient
Expand Down Expand Up @@ -83,6 +85,38 @@ def test_parsing_order():
assert order_obj.cancelable == False


@pytest.mark.asyncio
async def test_get_order(httpx_mock: HTTPXMock):
json_mock = get_mock_response()["single_order"]
mocked_token = mock_tokens()
token_store = LocalTokenStore()
if os.path.exists(Path(token_store.token_output_path)):
os.remove(token_store.token_output_path) # clean up before test

token_store.save_tokens(mocked_token)
httpx_mock.add_response(json=[json_mock]) # make it array type
from_entered_time = datetime.now() - timedelta(hours=3)
to_entered_time = datetime.now()
async with httpx.AsyncClient() as client:
cschwab_client = SchwabAsyncClient(
app_client_id="fake_id",
app_secret="fake_secret",
token_store=token_store,
tokens=mocked_token,
http_client=client,
)
retrieved_orders = await cschwab_client.get_orders_async(
account_number="123",
from_entered_time=from_entered_time,
to_entered_time=to_entered_time,
status=OrderStatus.FILLED,
)
assert retrieved_orders is not None
assert len(retrieved_orders) == 1
assert retrieved_orders[0].orderId == 456
assert retrieved_orders[0].cancelable == False


@pytest.mark.asyncio
async def test_get_single_account(httpx_mock: HTTPXMock):
json_mock = get_mock_response()["single_account"]
Expand Down