fix: correct WorldQuant daily alpha date filters
Deploy production / deploy (push) Successful in 52s
Deploy production / deploy (push) Successful in 52s
This commit is contained in:
@@ -350,9 +350,13 @@ class WqClient:
|
|||||||
# Daily intervals are [UTC midnight, next midnight). Submitted dates
|
# Daily intervals are [UTC midnight, next midnight). Submitted dates
|
||||||
# use the actual submission time, independently of creation or stage.
|
# use the actual submission time, independently of creation or stage.
|
||||||
field = "dateCreated" if submission == "UNSUBMITTED" else "dateSubmitted"
|
field = "dateCreated" if submission == "UNSUBMITTED" else "dateSubmitted"
|
||||||
params.update({f"{field}>=": date_from, f"{field}<": date_to, "order": field})
|
# BRAIN treats the query separator '=' as part of its comparison
|
||||||
|
# syntax: a '>=' key adds an extra '=' and makes the date invalid.
|
||||||
|
# Both bounds are inclusive upstream; exclude the next UTC midnight.
|
||||||
|
upper = (datetime.fromisoformat(date_to) - timedelta(microseconds=1)).isoformat()
|
||||||
|
params.update({f"{field}>": date_from, f"{field}<": upper, "order": field})
|
||||||
if field == "dateCreated":
|
if field == "dateCreated":
|
||||||
params["dateCreated<"] = min(before, date_to)
|
params["dateCreated<"] = min(before, upper)
|
||||||
return await self.get("/users/self/alphas", params)
|
return await self.get("/users/self/alphas", params)
|
||||||
|
|
||||||
async def alpha(self, alpha_id):
|
async def alpha(self, alpha_id):
|
||||||
|
|||||||
@@ -163,7 +163,9 @@ def create_test_app():
|
|||||||
r for r in records if (r["status"] == "UNSUBMITTED") == unsubmitted and r["hidden"] == hidden
|
r for r in records if (r["status"] == "UNSUBMITTED") == unsubmitted and r["hidden"] == hidden
|
||||||
]
|
]
|
||||||
for field in ("dateCreated", "dateSubmitted"):
|
for field in ("dateCreated", "dateSubmitted"):
|
||||||
for suffix in (">=", "<"):
|
if field + ">=" in request.url.params:
|
||||||
|
return httpx.Response(400, json=["Expected ISO 8601 datetime with timezone"])
|
||||||
|
for suffix in (">", "<"):
|
||||||
boundary = request.url.params.get(field + suffix)
|
boundary = request.url.params.get(field + suffix)
|
||||||
if boundary:
|
if boundary:
|
||||||
bound = datetime.fromisoformat(boundary).replace(tzinfo=timezone.utc)
|
bound = datetime.fromisoformat(boundary).replace(tzinfo=timezone.utc)
|
||||||
@@ -173,8 +175,8 @@ def create_test_app():
|
|||||||
if r.get(field)
|
if r.get(field)
|
||||||
and (
|
and (
|
||||||
datetime.fromisoformat(r[field]) >= bound
|
datetime.fromisoformat(r[field]) >= bound
|
||||||
if suffix == ">="
|
if suffix == ">"
|
||||||
else datetime.fromisoformat(r[field]) < bound
|
else datetime.fromisoformat(r[field]) <= bound
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
offset, limit = (
|
offset, limit = (
|
||||||
|
|||||||
@@ -318,12 +318,25 @@ async def test_scoped_date_query_parameters_and_no_platform_check(settings):
|
|||||||
|
|
||||||
def handler(request):
|
def handler(request):
|
||||||
requests.append(request)
|
requests.append(request)
|
||||||
return httpx.Response(200, json={"results": []})
|
# BRAIN parses the extra '=' as part of the datetime, returning HTTP 400.
|
||||||
|
if any(key.endswith(">=") for key in request.url.params):
|
||||||
|
return httpx.Response(400, json=["Expected ISO 8601 datetime with timezone"])
|
||||||
|
field = "dateCreated" if "status" in request.url.params else "dateSubmitted"
|
||||||
|
lower = datetime.fromisoformat(request.url.params[field + ">"])
|
||||||
|
upper = datetime.fromisoformat(request.url.params[field + "<"])
|
||||||
|
records = [
|
||||||
|
{"id": "midnight", field: "2025-01-01T00:00:00+00:00"},
|
||||||
|
{"id": "last", field: "2025-01-01T23:59:59.999999+00:00"},
|
||||||
|
{"id": "next", field: "2025-01-02T00:00:00+00:00"},
|
||||||
|
]
|
||||||
|
return httpx.Response(200, json={"results": [
|
||||||
|
row for row in records if lower <= datetime.fromisoformat(row[field]) <= upper
|
||||||
|
]})
|
||||||
|
|
||||||
client = WqClient(settings, transport=httpx.MockTransport(handler))
|
client = WqClient(settings, transport=httpx.MockTransport(handler))
|
||||||
client.credentials, client.authenticated = ("test@example.com", "test"), True
|
client.credentials, client.authenticated = ("test@example.com", "test"), True
|
||||||
for submission in ("UNSUBMITTED", "SUBMITTED"):
|
for submission in ("UNSUBMITTED", "SUBMITTED"):
|
||||||
await client.alphas(
|
result = await client.alphas(
|
||||||
submission,
|
submission,
|
||||||
True,
|
True,
|
||||||
100,
|
100,
|
||||||
@@ -331,10 +344,11 @@ async def test_scoped_date_query_parameters_and_no_platform_check(settings):
|
|||||||
date_from="2025-01-01T00:00:00+00:00",
|
date_from="2025-01-01T00:00:00+00:00",
|
||||||
date_to="2025-01-02T00:00:00+00:00",
|
date_to="2025-01-02T00:00:00+00:00",
|
||||||
)
|
)
|
||||||
|
assert [row["id"] for row in result["results"]] == ["midnight", "last"]
|
||||||
first, second = [dict(r.url.params) for r in requests]
|
first, second = [dict(r.url.params) for r in requests]
|
||||||
assert first["dateCreated>="] == "2025-01-01T00:00:00+00:00"
|
assert first["dateCreated>"] == "2025-01-01T00:00:00+00:00"
|
||||||
assert first["dateCreated<"] == "2025-01-02T00:00:00+00:00"
|
assert first["dateCreated<"] == "2025-01-01T23:59:59.999999+00:00"
|
||||||
assert second["dateSubmitted>="] == first["dateCreated>="]
|
assert second["dateSubmitted>"] == first["dateCreated>"]
|
||||||
assert second["dateSubmitted<"] == first["dateCreated<"]
|
assert second["dateSubmitted<"] == first["dateCreated<"]
|
||||||
assert "status!" in second and second["hidden"] == "true"
|
assert "status!" in second and second["hidden"] == "true"
|
||||||
assert all(r.method == "GET" and r.url.path == "/users/self/alphas" for r in requests)
|
assert all(r.method == "GET" and r.url.path == "/users/self/alphas" for r in requests)
|
||||||
|
|||||||
Reference in New Issue
Block a user