You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
24 KiB

3 weeks ago
import pytest
from kalshi import *
import kalshi
from piecewise import *
import json
from mocks import MockResponse
class TestConvertHundredLower:
def test_empty(self):
assert convert_contract_hundred_lower([]) == []
def test_single(self):
assert convert_contract_hundred_lower([(20, 100)]) == [(2000, 1)]
assert convert_contract_hundred_lower([(20, 110)]) == [(2000, 1)]
assert convert_contract_hundred_lower([(20, 310)]) == [(2000, 3)]
assert convert_contract_hundred_lower([(20, 10)]) == []
def test_two(self):
assert convert_contract_hundred_lower([(50, 10), (20, 100)]) == [(2000, 1)]
assert convert_contract_hundred_lower([(50, 10), (20, 90)]) == [(2000, 1)]
assert convert_contract_hundred_lower([(50, 10), (20, 91)]) == [(2000, 1)]
assert convert_contract_hundred_lower([(50, 10), (20, 89)]) == []
assert convert_contract_hundred_lower([(50, 100), (20, 91)]) == [(5000, 1)]
assert convert_contract_hundred_lower([(50, 109), (20, 91)]) == [(5000, 1), (2000, 1)]
assert convert_contract_hundred_lower([(50, 109), (20, 92)]) == [(5000, 1), (2000, 1)]
assert convert_contract_hundred_lower([(50, 109), (20, 90)]) == [(5000, 1)]
assert convert_contract_hundred_lower([(50, 209), (20, 192)]) == [(5000, 2), (2000, 2)]
assert convert_contract_hundred_lower([(50, 209), (20, 190)]) == [(5000, 2), (2000, 1)]
def test_more(self):
assert convert_contract_hundred_lower([(50, 110), (20, 230), (3, 60)]) == [(5000, 1), (2000, 2), (300, 1)]
assert convert_contract_hundred_lower([(50, 110), (20, 229), (3, 60)]) == [(5000, 1), (2000, 2)]
assert convert_contract_hundred_lower([(50, 110), (20, 229), (3, 160)]) == [(5000, 1), (2000, 2), (300, 1)]
assert convert_contract_hundred_lower([(50, 111), (20, 229), (3, 160)]) == [(5000, 1), (2000, 2), (300, 2)]
class TestConvertSPRulebook:
def test_or_lower(self):
assert convert_sp_rulebook({
"Above/Below/Between": "below",
"Cap_strike": "NA",
"Date": "November 04, 2022",
"Floor_strike": "NA",
"Value": "3600",
"contract_ticker": "INX"
}) == (None, 359999)
def test_or_higher(self):
assert convert_sp_rulebook({
"Above/Below/Between": "above",
"Cap_strike": "NA",
"Date": "November 04, 2022",
"Floor_strike": "NA",
"Value": "4249.99",
"contract_ticker": "INX"
}) == (425000, None)
def test_between(self):
assert convert_sp_rulebook({
"Above/Below/Between": "between",
"Cap_strike": "3999.99",
"Date": "November 04, 2022",
"Floor_strike": "3950",
"Value": "3950-3999.99",
"contract_ticker": "INX"
}) == (395000, 399999)
class TestParseOrderbookMessage:
def test_empty(self):
assert parse_orderbook_message({ "type": "orderbook_snapshot", "sid": 3, "seq": 1, "msg": { "market_id": "id123" }}) == ("id123", [], [])
assert parse_orderbook_message({ "type": "orderbook_snapshot", "sid": 3, "seq": 1, "msg": { "market_id": "id123", "no": [] }}) == ("id123", [], [])
def test_yes(self):
assert parse_orderbook_message({ "type": "orderbook_snapshot", "sid": 5, "seq": 1, "msg": { "market_id": "id123", "yes": [ [ 1, 100 ], [ 3, 500 ], [ 9, 10 ], [ 10, 20 ] ]} }) == ("id123", [(10, 20), (9, 10), (3, 500), (1, 100)], [])
def test_no(self):
assert parse_orderbook_message({ "type": "orderbook_snapshot", "sid": 5, "seq": 1, "msg": { "market_id": "id123", "no": [ [ 5, 2500 ], [ 25, 1000 ], [ 65, 150 ], [ 66, 100 ], [ 68, 8 ], [ 75, 128 ] ] } }) == ("id123", [], [(25, 128), (32, 8), (34, 100), (35, 150), (75, 1000), (95, 2500)])
def test_both(self):
assert parse_orderbook_message({ "type": "orderbook_snapshot", "sid": 5, "seq": 1, "msg": { "market_id": "id123", "yes": [ [ 1, 100 ], [ 3, 500 ], [ 9, 10 ], [ 10, 20 ] ], "no": [ [ 5, 2500 ], [ 25, 1000 ], [ 65, 150 ], [ 66, 100 ], [ 68, 8 ], [ 75, 128 ] ] } }) == ("id123", [(10, 20), (9, 10), (3, 500), (1, 100)], [(25, 128), (32, 8), (34, 100), (35, 150), (75, 1000), (95, 2500)])
class TestCalcFee:
def test_one_normal(self):
for p, ans in [[1, 1], [5, 1], [10, 1], [15, 1], [20, 2], [25, 2], [30, 2], [35, 2], [40, 2], [45, 2], [50, 2], [55, 2], [60, 2], [65, 2], [70, 2], [75, 2], [80, 2], [85, 1], [90, 1], [95, 1], [99, 1]]:
assert calc_fee(p, 1, False) == ans
def test_100_normal(self):
for p, ans in [[1, 7], [5, 34], [10, 63], [15, 90], [20, 112], [25, 132], [30, 147], [35, 160], [40, 168], [45, 174], [50, 175], [55, 174], [60, 168], [65, 160], [70, 147], [75, 132], [80, 112], [85, 90], [90, 63], [95, 34], [99, 7]]:
assert calc_fee(p*100, 100, False) == ans
def test_one_index(self):
for p, ans in [[1, 1], [5, 1], [10, 1], [15, 1], [20, 1], [25, 1], [30, 1], [35, 1], [40, 1], [45, 1], [50, 1], [55, 1], [60, 1], [65, 1], [70, 1], [75, 1], [80, 1], [85, 1], [90, 1], [95, 1], [99, 1]]:
assert calc_fee(p, 1, True) == ans
def test_100_index(self):
for p, ans in [[1, 4], [5, 17], [10, 32], [15, 45], [20, 56], [25, 66], [30, 74], [35, 80], [40, 84], [45, 87], [50, 88], [55, 87], [60, 84], [65, 80], [70, 74], [75, 66], [80, 56], [85, 45], [90, 32], [95, 17], [99, 4]]:
assert calc_fee(p*100, 100, True) == ans
class TestConvToPC:
@staticmethod
def mock_calcfee(p, cs, is_index):
assert p==2000
assert cs==100
assert is_index==True
return 103
def setup_method(self):
self._calc_fee = kalshi.calc_fee
kalshi.calc_fee = TestConvToPC.mock_calcfee
def teardown_method(self):
kalshi.calc_fee = self._calc_fee
def test_ask_left(self):
assert conv_ask_to_pc((None, 30000), 2000, 3, True, True) == (Piecewise_Constant(10000-2000-103, [(30001, -2000-103)]), 3, 2000)
def test_ask_right(self):
assert conv_ask_to_pc((30000, None), 2000, 3, True, True) == (Piecewise_Constant(-2000-103, [(30000, 10000-2000-103)]), 3, 2000)
def test_ask_both(self):
assert conv_ask_to_pc((30000, 50000), 2000, 3, True, True) == (Piecewise_Constant(-2000-103, [(30000, 10000-2000-103), (50001, -2000-103)]), 3, 2000)
def test_bid_left(self):
assert conv_bid_to_pc((None, 30000), 2000, 3, True, True) == (Piecewise_Constant(-10000+2000-103, [(30001, 2000-103)]), 3, 2000)
def test_bid_right(self):
assert conv_bid_to_pc((30000, None), 2000, 3, True, True) == (Piecewise_Constant(2000-103, [(30000, -10000+2000-103)]), 3, 2000)
def test_bid_both(self):
assert conv_bid_to_pc((30000, 50000), 2000, 3, True, True) == (Piecewise_Constant(2000-103, [(30000, -10000+2000-103), (50001, 2000-103)]), 3, 2000)
@pytest.mark.asyncio
async def test_markets_from_ticker(monkeypatch):
def mock_get(self, url):
assert url=="https://trading-api.kalshi.com/v1/events/INXW-22NOV04"
return MockResponse(json.loads("""{"event":{"ticker":"INXW-22NOV04","series_ticker":"INX","target_datetime":"2022-11-04T20:00:00Z","mutually_exclusive":true,"mutually_exclusive_side":"yes","title":"What will the value of the S&P 500 be at the end of Nov 4, 2022","category":"Financials","tags":["Stocks"],"min_tick_size":"$0.01","settle_details":"The market will close at 4:00 PM ET on || Date ||. The market will expire at the sooner of the first 7:00 PM ET after the release of the data, or one week after || Date ||.\\n\\nPursuant to the Kalshi Rulebook, the Exchange has modified the Source Agency and Underlying for indices markets. See the rules for more information.","settlement_sources":[{"url":"https://www.google.com/finance/quote/.INX:INDEXSP?hl=en","name":"For example, Google Finance"}],"description_context":"","underlying":"If the end-of-day S&P 500 index value for || Date || is ||Above/Below/Between|| ||Value||, then the market resolves to Yes.","metrics_tags":["Nasdaq","QQQ","Nasdaq-100","S&P","S&P 500","Standard & Poor's","Stock Market","Stocks","Equities","Tech","SPY","SPX"],"mini_title":"TEMP","sub_title":"On Nov 4, 2022","markets":[{"id":"222299db-a2ce-444b-ace7-ea4449c8ba2e","ticker_name":"INXW-22NOV04-T3600","create_date":"2022-10-28T20:05:34.870432Z","list_date":"2022-10-28T20:30:00Z","open_date":"2022-10-28T20:30:00Z","close_date":"2022-11-04T20:00:00Z","expiration_date":"2022-11-11T23:00:00Z","status":"active","expiration_value":"","result":"","yes_bid":2,"yes_ask":30,"last_price":1,"previous_yes_bid":1,"previous_yes_ask":3,"previous_price":5,"volume":4604,"recent_volume":1614,"open_interest":3850,"liquidity":386074,"dollar_volume":2302,"dollar_recent_volume":807,"dollar_open_interest":1925,"sub_title":"3,599.99 or lower","title":"Will the S&P 500 be below 3600 at the end of Nov 4, 2022?","mini_title":"S&P500 value","name":"3599.99 or below","can_close_early":true,"rulebook_variables":{"Above/Below/Between":"below","Cap_strike":"NA","Date":"November 04, 2022","Floor_strike":"NA","Value":"3600","contract_ticker":"INX"},"risk_limit_cents":0},{"id":"95d88ef0-94d3-4acd-9c60-848d87f2dc42","ticker_name":"INXW-22NOV04-B3625","create_date":"2022-10-28T20:05:34.870432Z","list_date":"2022-10-28T20:30:00Z","open_date":"2022-10-28T20:30:00Z","close_date":"2022-11-04T20:00:00Z","expiration_date":"2022-11-11T23:00:00Z","status":"active","expiration_value":"","result":"","yes_bid":4,"yes_ask":8,"last_price":9,"previous_yes_bid":2,"previous_yes_ask":25,"previous_price":1,"volume":8094,"recent_volume":4788,"open_interest":5600,"liquidity":552367,"dollar_volume":4047,"dollar_recent_volume":2394,"dollar_open_interest":2800,"sub_title":"3,600 to 3,649.99","title":"Will the S&P 500 be between 3600 and 3649.99 at the end of Nov 4, 2022?","mini_title":"S&P500 value","name":"3600 to 3649.99","can_close_early":true,"rulebook_variables":{"Above/Below/Between":"between","Cap_strike":"3649.99","Date":"November 04, 2022","Floor_strike":"3600","Value":"3600-3649.99","contract_ticker":"INX"},"risk_limit_cents":0},{"id":"095be654-b0dc-442d-b3f8-3a684ae41242","ticker_name":"INXW-22NOV04-B3675","create_date":"2022-10-28T20:05:34.870432Z","list_date":"2022-10-28T20:30:00Z","open_date":"2022-10-28T20:30:00Z","close_date":"2022-11-04T20:00:00Z","expiration_date":"2022-11-11T23:00:00Z","status":"active","expiration_value":"","result":"","yes_bid":10,"yes_ask":30,"last_price":27,"previous_yes_bid":3,"previous_yes_ask":25,"previous_price":25,"volume":5302,"recent_volume":4722,"open_interest":5074,"liquidity":388560,"dollar_volume":2651,"dollar_recent_volume":2361,"dollar_open_interest":2537,"sub_title":"3,650 to 3,699.99","title":"Will the S&P 500 be between 3650 and 3699.99 at the end of Nov 4, 2022?","mini_title":"S&P500 value","name":"3650 to 3699.99","can_close_early":true,"rulebook_variables":{"Above/Below/Between":"between","Cap_strike":"3699.99","Date":"November 04, 2022","Floor_strike":"3650","Value":"3650-3699.99","contract_ticker":"INX"},"risk_limit_cents":0},{"id":"478093bf-8dc5-420d-af28-58a88d9a2404","ticker_name":"INXW-22N
, 200)
with monkeypatch.context() as m:
m.setattr("aiohttp.ClientSession.get", mock_get)
async with aiohttp.ClientSession() as s:
ks = KalshiSession(s)
lims = await ks.markets_from_ticker("INXW-22NOV04", convert_sp_rulebook)
assert lims=={
"222299db-a2ce-444b-ace7-ea4449c8ba2e": (None, 359999),
"95d88ef0-94d3-4acd-9c60-848d87f2dc42": (360000, 364999),
"095be654-b0dc-442d-b3f8-3a684ae41242": (365000, 369999),
"478093bf-8dc5-420d-af28-58a88d9a2404": (370000, 374999),
"86f602c6-25a4-4e81-959b-db217827002c": (375000, 379999),
"dcff5f0e-18c4-4584-82fa-88bc2896694a": (380000, 384999),
"92c30c3b-8f7d-4595-9768-d90cff3bc380": (385000, 389999),
"77b607b9-e6bd-49f4-b7ea-cc5467b69821": (390000, 394999),
"fbb706b8-f6db-4b1a-aee2-3960aa112bcc": (395000, 399999),
"c790e6cf-a724-497c-88f5-beab9827b7ec": (400000, 404999),
"b3132a7c-8b6a-4d10-97b5-93e5185a0115": (405000, 409999),
"8e5817ba-13a0-4091-b7ad-4f06107c4b88": (410000, 414999),
"baaebca4-d251-4e10-848f-4a221b4a3ff1": (415000, 419999),
"389b8a4a-1f6d-42ac-bddc-1d4a1db071b9": (420000, 424999),
"1671f853-2757-4268-81fe-5f7ebe0a021c": (425000, None),
}