diff --git a/testy/output_metriky_tradeList.py b/testy/output_metriky_tradeList.py new file mode 100644 index 0000000..46d4233 --- /dev/null +++ b/testy/output_metriky_tradeList.py @@ -0,0 +1,1046 @@ +import pandas as pd +from v2realbot.utils.utils import AttributeDict + +from v2realbot.common.model import TradeEvent, TradeUpdate, Order +from v2realbot.enums.enums import OrderSide, OrderStatus, OrderType +import datetime +from uuid import UUID + +#testing tradelist +tradeList = [ + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('67affc55-fa98-446f-8ac0-eb0bb494f450'), + order=Order( + id=UUID('ae8b1fff-8a87-4ec2-af7d-48765c62afc5'), + submitted_at=datetime.datetime(2023, 3, 24, 17, 58, 1, 538364), + filled_at=datetime.datetime(2023, 3, 24, 17, 58, 30, 735317), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.56, + side=OrderSide.BUY, + limit_price=42.56 + ), + timestamp=datetime.datetime(2023, 3, 24, 17, 58, 30, 735317), + position_qty=10.0, + price=42.56, + qty=10.0, + value=425.6, + cash=99574.4, + pos_avg_price=42.56 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('51b872ed-98f1-4540-af13-6d8beb6ab660'), + order=Order( + id=UUID('5cae451b-6c46-47d5-8a43-023569eebcac'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 0, 43, 790484), + filled_at=datetime.datetime(2023, 3, 24, 18, 0, 46, 336552), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.51, + side=OrderSide.BUY, + limit_price=42.51 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 0, 46, 336552), + position_qty=20.0, + price=42.51, + qty=10.0, + value=425.09999999999997, + cash=99149.29999999999, + pos_avg_price=42.535000000000004 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('86e67324-8b74-4f67-bac7-16f2564f117d'), + order=Order( + id=UUID('f04a52b4-74e0-4de8-9ec3-a89d608e2c8d'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 3, 20, 914489), + filled_at=datetime.datetime(2023, 3, 24, 18, 3, 22, 529390), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.44, + side=OrderSide.BUY, + limit_price=42.44 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 3, 22, 529390), + position_qty=30.0, + price=42.44, + qty=10.0, + value=424.4, + cash=98724.9, + pos_avg_price=42.50333333333333 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('8ef5eb96-9dfa-486b-b52b-bd1cc10ab75d'), + order=Order( + id=UUID('fae4fd0d-d1e4-46e2-85e5-f32708780e77'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 3, 22, 575390), + filled_at=datetime.datetime(2023, 3, 24, 18, 5, 37, 585264), + canceled_at=None, + symbol='C', + qty=30, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=30, + filled_avg_price=42.52, + side=OrderSide.SELL, + limit_price=42.52 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 5, 37, 585264), + position_qty=0.0, + price=42.52, + qty=30.0, + value=1275.6000000000001, + cash=100000.5, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('1b3ea95a-b51c-4894-83e1-82364695047a'), + order=Order( + id=UUID('40aef04b-677f-4429-9a6f-05de170df1ae'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 10, 45, 566915), + filled_at=datetime.datetime(2023, 3, 24, 18, 11, 6, 387022), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.42, + side=OrderSide.BUY, + limit_price=42.42 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 11, 6, 387022), + position_qty=10.0, + price=42.42, + qty=10.0, + value=424.20000000000005, + cash=99576.3, + pos_avg_price=42.42 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('44baaa7c-4ff6-4e16-ac4a-0ae45a050c03'), + order=Order( + id=UUID('21b961ac-8129-4800-babd-81bb87eccfda'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 13, 20, 777011), + filled_at=datetime.datetime(2023, 3, 24, 18, 14, 38, 586145), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.38, + side=OrderSide.BUY, + limit_price=42.38 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 14, 38, 586145), + position_qty=20.0, + price=42.38, + qty=10.0, + value=423.8, + cash=99152.5, + pos_avg_price=42.4 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('28c9f825-4300-46ce-b73e-3af795a836a9'), + order=Order( + id=UUID('28c897f5-cb12-4b2c-9b20-abde056e1b12'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 14, 38, 632145), + filled_at=datetime.datetime(2023, 3, 24, 18, 15, 13, 203500), + canceled_at=None, + symbol='C', + qty=20, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=20, + filled_avg_price=42.42, + side=OrderSide.SELL, + limit_price=42.42 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 15, 13, 203500), + position_qty=0.0, + price=42.42, + qty=20.0, + value=848.4000000000001, + cash=100000.9, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('445a98ae-6fbe-415d-88e8-f98f5c6fb411'), + order=Order( + id=UUID('f1e8412c-7e36-4d0c-97a7-88e5dbab9b25'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 20, 0, 372031), + filled_at=datetime.datetime(2023, 3, 24, 18, 20, 10, 239271), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.39, + side=OrderSide.BUY, + limit_price=42.39 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 20, 10, 239271), + position_qty=10.0, + price=42.39, + qty=10.0, + value=423.9, + cash=99577.0, + pos_avg_price=42.39 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('e2e5cf75-6517-459b-89f8-f967a3442737'), + order=Order( + id=UUID('cf1cab4c-9e39-46a9-a804-d2e2337340bf'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 20, 10, 285271), + filled_at=datetime.datetime(2023, 3, 24, 18, 20, 31, 861599), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.41, + side=OrderSide.SELL, + limit_price=42.41 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 20, 31, 861599), + position_qty=0.0, + price=42.41, + qty=10.0, + value=424.09999999999997, + cash=100001.1, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('0f5308ae-bea1-4412-8922-344f6dac10ef'), + order=Order( + id=UUID('6f16c0c0-a86e-4e6f-b07e-7eb76347b223'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 43, 20, 376929), + filled_at=datetime.datetime(2023, 3, 24, 18, 45, 52, 906738), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.99, + side=OrderSide.BUY, + limit_price=42.99 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 45, 52, 906738), + position_qty=10.0, + price=42.99, + qty=10.0, + value=429.90000000000003, + cash=99571.20000000001, + pos_avg_price=42.99 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('98f17b2e-4392-47e5-8697-c23878e1c71a'), + order=Order( + id=UUID('afc5a626-c3cb-4cf9-b887-7571dded2f6c'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 45, 52, 952738), + filled_at=datetime.datetime(2023, 3, 24, 18, 46, 0, 627175), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=43.01, + side=OrderSide.SELL, + limit_price=43.01 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 46, 0, 627175), + position_qty=0.0, + price=43.01, + qty=10.0, + value=430.09999999999997, + cash=100001.30000000002, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('5431e393-291c-4828-be51-706acc39deda'), + order=Order( + id=UUID('a3a6a1d1-8bf8-4fc6-995d-0d0766443c55'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 49, 41, 540044), + filled_at=datetime.datetime(2023, 3, 24, 18, 50, 47, 441926), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.93, + side=OrderSide.BUY, + limit_price=42.93 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 50, 47, 441926), + position_qty=10.0, + price=42.93, + qty=10.0, + value=429.3, + cash=99572.00000000001, + pos_avg_price=42.93 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('f10ca407-0604-4e2e-b0cf-4e4243e57947'), + order=Order( + id=UUID('246d819c-6e1d-4fc0-a91e-17404fcc5cea'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 50, 47, 487926), + filled_at=datetime.datetime(2023, 3, 24, 18, 54, 23, 727098), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.95, + side=OrderSide.SELL, + limit_price=42.95 + ), + timestamp=datetime.datetime(2023, 3, 24, 18, 54, 23, 727098), + position_qty=0.0, + price=42.95, + qty=10.0, + value=429.5, + cash=100001.50000000001, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('9fcef2d1-2b55-4a74-9927-8463a74e75e2'), + order=Order( + id=UUID('f250e354-2291-499f-b1f0-d56788211959'), + submitted_at=datetime.datetime(2023, 3, 24, 18, 52, 20, 117195), + filled_at=datetime.datetime(2023, 3, 24, 19, 5, 39, 193071), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.86, + side=OrderSide.BUY, + limit_price=42.86 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 5, 39, 193071), + position_qty=10.0, + price=42.86, + qty=10.0, + value=428.6, + cash=99572.90000000001, + pos_avg_price=42.86 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('ea4b0db4-998e-4e2a-b614-98b157106164'), + order=Order( + id=UUID('570e9c37-5c4e-4437-9dd4-a642029ca6a7'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 5, 39, 239071), + filled_at=datetime.datetime(2023, 3, 24, 19, 5, 46, 747462), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.88, + side=OrderSide.SELL, + limit_price=42.88 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 5, 46, 747462), + position_qty=0.0, + price=42.88, + qty=10.0, + value=428.8, + cash=100001.70000000001, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('abf993dc-5aee-4b89-b48c-92bbfcb4efe4'), + order=Order( + id=UUID('f3be9459-1c89-4594-bee0-b64ace83a12e'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 7, 22, 109412), + filled_at=datetime.datetime(2023, 3, 24, 19, 7, 25, 509392), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.79, + side=OrderSide.BUY, + limit_price=42.79 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 7, 25, 509392), + position_qty=10.0, + price=42.79, + qty=10.0, + value=427.9, + cash=99573.80000000002, + pos_avg_price=42.79 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('b30b01cf-b0da-4166-a5ee-9e398ce0caf7'), + order=Order( + id=UUID('44687505-271f-423d-b5eb-4022a3b0042e'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 7, 25, 555392), + filled_at=datetime.datetime(2023, 3, 24, 19, 7, 49, 238057), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.81, + side=OrderSide.SELL, + limit_price=42.81 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 7, 49, 238057), + position_qty=0.0, + price=42.81, + qty=10.0, + value=428.1, + cash=100001.90000000002, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('3d0bde12-75e4-4589-b51d-98f351c27f51'), + order=Order( + id=UUID('b4d1deb5-bedb-4792-87a2-d93d7a791245'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 42, 0, 124666), + filled_at=datetime.datetime(2023, 3, 24, 19, 42, 3, 369522), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.97, + side=OrderSide.BUY, + limit_price=42.97 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 42, 3, 369522), + position_qty=10.0, + price=42.97, + qty=10.0, + value=429.7, + cash=99572.20000000003, + pos_avg_price=42.97 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('726bc5e6-94fd-4618-bee0-91339dbfa88c'), + order=Order( + id=UUID('b32bb6d0-c972-45a5-b6ac-144273e956ea'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 42, 3, 415522), + filled_at=datetime.datetime(2023, 3, 24, 19, 42, 34, 428260), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.99, + side=OrderSide.SELL, + limit_price=42.99 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 42, 34, 428260), + position_qty=0.0, + price=42.99, + qty=10.0, + value=429.90000000000003, + cash=100002.10000000002, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('0f3ab616-6616-4ba5-b32f-8c7f1a6be8cb'), + order=Order( + id=UUID('345162e0-5e7b-4e0c-b5bf-dffad0508da9'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 42, 44, 484124), + filled_at=datetime.datetime(2023, 3, 24, 19, 49, 6, 219276), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.98, + side=OrderSide.BUY, + limit_price=42.98 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 49, 6, 219276), + position_qty=10.0, + price=42.98, + qty=10.0, + value=429.79999999999995, + cash=99572.30000000002, + pos_avg_price=42.98 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('53e0171c-6246-40ee-9dd8-f9155be32f11'), + order=Order( + id=UUID('826b174d-c894-4c7b-a25e-b42b23eaabad'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 49, 6, 265276), + filled_at=datetime.datetime(2023, 3, 24, 19, 49, 57, 528455), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=43.005, + side=OrderSide.SELL, + limit_price=43.0 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 49, 57, 528455), + position_qty=0.0, + price=43.005, + qty=10.0, + value=430.05, + cash=100002.35000000002, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('d827dc6f-51e2-4149-acd8-e438a271fa75'), + order=Order( + id=UUID('d931a776-2739-41ba-bd16-d9b45dff59ec'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 52, 1, 100351), + filled_at=datetime.datetime(2023, 3, 24, 19, 52, 7, 321771), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.94, + side=OrderSide.BUY, + limit_price=42.94 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 52, 7, 321771), + position_qty=10.0, + price=42.94, + qty=10.0, + value=429.4, + cash=99572.95000000003, + pos_avg_price=42.94 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('20d15c7a-23c0-4815-85df-8a302e2e0f39'), + order=Order( + id=UUID('0419ba73-ad51-4df6-b211-ac4c42a6e032'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 28, 43, 668847), + filled_at=datetime.datetime(2023, 3, 24, 19, 52, 41, 652899), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.9, + side=OrderSide.BUY, + limit_price=42.9 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 52, 41, 652899), + position_qty=20.0, + price=42.9, + qty=10.0, + value=429.0, + cash=99143.95000000003, + pos_avg_price=42.92 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('a2f8bc9b-d2ad-4a0a-a5f3-2cc728d2e541'), + order=Order( + id=UUID('36d89e04-fdfc-410d-9608-fa6517a3034d'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 54, 43, 440852), + filled_at=datetime.datetime(2023, 3, 24, 19, 54, 49, 709012), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.87, + side=OrderSide.BUY, + limit_price=42.87 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 54, 49, 709012), + position_qty=30.0, + price=42.87, + qty=10.0, + value=428.7, + cash=98715.25000000003, + pos_avg_price=42.903333333333336 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('dace8d0b-6618-498c-aaea-7d6e43903c92'), + order=Order( + id=UUID('57222023-d25e-461b-811a-1abc87390971'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 54, 49, 755012), + filled_at=datetime.datetime(2023, 3, 24, 19, 55, 45, 671150), + canceled_at=None, + symbol='C', + qty=30, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=30, + filled_avg_price=42.92, + side=OrderSide.SELL, + limit_price=42.92 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 55, 45, 671150), + position_qty=0.0, + price=42.92, + qty=30.0, + value=1287.6000000000001, + cash=100002.85000000003, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('3ce200d5-3e8d-4af8-818d-41e3f49e91f9'), + order=Order( + id=UUID('09ada304-3920-4d21-a7c5-520116f60161'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 8, 3, 126555), + filled_at=datetime.datetime(2023, 3, 24, 19, 59, 28, 62458), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.83, + side=OrderSide.BUY, + limit_price=42.83 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 59, 28, 62458), + position_qty=10.0, + price=42.83, + qty=10.0, + value=428.29999999999995, + cash=99574.55000000003, + pos_avg_price=42.83 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('51b1ef83-e486-44a1-9809-fd5ebca18a50'), + order=Order( + id=UUID('c8894c95-83bc-455e-8501-6622e74ad267'), + submitted_at=datetime.datetime(2023, 3, 24, 19, 59, 28, 108458), + filled_at=datetime.datetime(2023, 3, 24, 19, 59, 40, 517988), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.85, + side=OrderSide.SELL, + limit_price=42.85 + ), + timestamp=datetime.datetime(2023, 3, 24, 19, 59, 40, 517988), + position_qty=0.0, + price=42.85, + qty=10.0, + value=428.5, + cash=100003.05000000003, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('1a0724f7-53de-42e3-9917-b65ecca4e7a0'), + order=Order( + id=UUID('14783679-6871-496c-8875-60c3d6ae0135'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 0, 21, 449585), + filled_at=datetime.datetime(2023, 3, 24, 20, 0, 25, 189635), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.84, + side=OrderSide.BUY, + limit_price=42.84 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 0, 25, 189635), + position_qty=10.0, + price=42.84, + qty=10.0, + value=428.40000000000003, + cash=99574.65000000004, + pos_avg_price=42.84 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('087b5b76-0cc5-4462-971b-782fe4c4c6ad'), + order=Order( + id=UUID('3b5bf7fb-cba2-4bfb-b3b7-74e191caf928'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 0, 25, 235635), + filled_at=datetime.datetime(2023, 3, 24, 20, 1, 49, 107372), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.86, + side=OrderSide.SELL, + limit_price=42.86 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 1, 49, 107372), + position_qty=0.0, + price=42.86, + qty=10.0, + value=428.6, + cash=100003.25000000004, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('0302b8e0-d427-4f93-9b23-ee1da32149bd'), + order=Order( + id=UUID('446f4bab-3bd7-4bbb-ba9b-1d0445cc6371'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 8, 0, 534518), + filled_at=datetime.datetime(2023, 3, 24, 20, 8, 18, 36437), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.83, + side=OrderSide.BUY, + limit_price=42.83 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 8, 18, 36437), + position_qty=10.0, + price=42.83, + qty=10.0, + value=428.29999999999995, + cash=99574.95000000004, + pos_avg_price=42.83 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('1c191c3f-fe56-4486-92f2-b4ab2e0d1d24'), + order=Order( + id=UUID('cb920785-4520-44e5-b6af-978da3927c59'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 10, 41, 294273), + filled_at=datetime.datetime(2023, 3, 24, 20, 10, 45, 568943), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.78, + side=OrderSide.BUY, + limit_price=42.78 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 10, 45, 568943), + position_qty=20.0, + price=42.78, + qty=10.0, + value=427.8, + cash=99147.15000000004, + pos_avg_price=42.80499999999999 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('ec034230-58ba-4300-82c1-7d30399d1be0'), + order=Order( + id=UUID('f111ec92-77d2-4e38-b789-90d6ed471c76'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 10, 45, 614943), + filled_at=datetime.datetime(2023, 3, 24, 20, 11, 12, 853893), + canceled_at=None, + symbol='C', + qty=20, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=20, + filled_avg_price=42.82, + side=OrderSide.SELL, + limit_price=42.82 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 11, 12, 853893), + position_qty=0.0, + price=42.82, + qty=20.0, + value=856.4, + cash=100003.55000000003, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('2343a817-dcd9-42a5-8645-bf9e9fcb41a2'), + order=Order( + id=UUID('24f0e7a7-b1ce-42b6-9514-8721b240b31d'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 14, 40, 530031), + filled_at=datetime.datetime(2023, 3, 24, 20, 14, 57, 348700), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.74, + side=OrderSide.BUY, + limit_price=42.74 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 14, 57, 348700), + position_qty=10.0, + price=42.74, + qty=10.0, + value=427.40000000000003, + cash=99576.15000000004, + pos_avg_price=42.74 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('57f57435-ff77-4e6f-96d6-b29b725c4693'), + order=Order( + id=UUID('b8470e7b-6773-47bb-984c-ab44832b3b3b'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 14, 57, 394700), + filled_at=datetime.datetime(2023, 3, 24, 20, 15, 12, 621144), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.76, + side=OrderSide.SELL, + limit_price=42.76 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 15, 12, 621144), + position_qty=0.0, + price=42.76, + qty=10.0, + value=427.59999999999997, + cash=100003.75000000004, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('069b4a2d-0377-4345-96b6-74e9fae89d9e'), + order=Order( + id=UUID('9a4bbe02-fc9e-4261-95d3-d609737662a9'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 25, 41, 185936), + filled_at=datetime.datetime(2023, 3, 24, 20, 27, 34, 90412), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.86, + side=OrderSide.BUY, + limit_price=42.86 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 27, 34, 90412), + position_qty=10.0, + price=42.86, + qty=10.0, + value=428.6, + cash=99575.15000000004, + pos_avg_price=42.86 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('6bdd0e17-b1c2-4080-8f26-c980d615f31f'), + order=Order( + id=UUID('070c371c-f8d4-4437-b42f-6a94d3962d7b'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 27, 34, 136412), + filled_at=datetime.datetime(2023, 3, 24, 20, 28, 24, 695266), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.88, + side=OrderSide.SELL, + limit_price=42.88 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 28, 24, 695266), + position_qty=0.0, + price=42.88, + qty=10.0, + value=428.8, + cash=100003.95000000004, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('303bbd02-4d8b-4940-9878-52c1dca92c73'), + order=Order( + id=UUID('247f87b0-4d97-4527-bcf1-2e0679c546b0'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 35, 0, 150590), + filled_at=datetime.datetime(2023, 3, 24, 20, 35, 23, 954682), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.9, + side=OrderSide.BUY, + limit_price=42.9 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 35, 23, 954682), + position_qty=10.0, + price=42.9, + qty=10.0, + value=429.0, + cash=99574.95000000004, + pos_avg_price=42.9 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('697ed9c5-40c3-439c-9811-29c9f4d74487'), + order=Order( + id=UUID('3ce9a256-059e-43ed-a290-286fa310fa21'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 35, 24, 682), + filled_at=datetime.datetime(2023, 3, 24, 20, 36, 15, 43220), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.92, + side=OrderSide.SELL, + limit_price=42.92 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 36, 15, 43220), + position_qty=0.0, + price=42.92, + qty=10.0, + value=429.20000000000005, + cash=100004.15000000004, + pos_avg_price=0.0 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('e0a33f84-91d1-4e89-95d9-e95a3a90b0fb'), + order=Order( + id=UUID('2889c4db-7c12-4b17-b35f-c81f53625c71'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 48, 0, 466959), + filled_at=datetime.datetime(2023, 3, 24, 20, 48, 0, 901059), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.91, + side=OrderSide.BUY, + limit_price=42.91 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 48, 0, 901059), + position_qty=10.0, + price=42.91, + qty=10.0, + value=429.09999999999997, + cash=99575.05000000003, + pos_avg_price=42.91 + ), + TradeUpdate( + event=TradeEvent.FILL, + execution_id=UUID('bca37e22-3ec2-4cf4-9ce8-779675469324'), + order=Order( + id=UUID('65a65038-7cda-4b18-aa5b-c48af539d1ba'), + submitted_at=datetime.datetime(2023, 3, 24, 20, 48, 0, 947059), + filled_at=datetime.datetime(2023, 3, 24, 20, 48, 55, 262008), + canceled_at=None, + symbol='C', + qty=10, + status=OrderStatus.FILLED, + order_type=OrderType.LIMIT, + filled_qty=10, + filled_avg_price=42.93, + side=OrderSide.SELL, + limit_price=42.93 + ), + timestamp=datetime.datetime(2023, 3, 24, 20, 48, 55, 262008), + position_qty=0.0, + price=42.93, + qty=10.0, + value=429.3, + cash=100004.35000000003, + pos_avg_price=0.0 + ) +] + +#create pandas +trade_dict = AttributeDict(orderid=[],timestamp=[],symbol=[],side=[],order_type=[],qty=[],price=[],position_qty=[],value=[],cash=[],pos_avg_price=[]) +for t in tradeList: + if t.event == TradeEvent.FILL: + trade_dict.orderid.append(str(t.order.id)) + trade_dict.timestamp.append(t.timestamp) + trade_dict.symbol.append(t.order.symbol) + trade_dict.side.append(t.order.side) + trade_dict.qty.append(t.qty) + trade_dict.price.append(t.price) + trade_dict.position_qty.append(t.position_qty) + trade_dict.value.append(t.value) + trade_dict.cash.append(t.cash) + trade_dict.order_type.append(t.order.order_type) + trade_dict.pos_avg_price.append(t.pos_avg_price) + +trade_df = pd.DataFrame(trade_dict) +trade_df = trade_df.set_index('timestamp',drop=False) + +#max positions- +max_positions = trade_df.groupby('side')['qty'].value_counts().reset_index(name='count').sort_values(['qty'], ascending=False) +max_positions = max_positions[max_positions['side'] == OrderSide.SELL] +max_positions = max_positions.drop(columns=['side'], axis=1) + +#filt = max_positions['side'] == 'OrderSide.BUY' +res = dict(zip(max_positions['qty'], max_positions['count'])) + +ouput_dict=dict(maxpos=str(res)) + +print(ouput_dict) +#a = trade_df.value_counts(subset=['position_qty']) +#print(max_positions.to_dict('records')) +#print(max_positions.to_dict('list')) +#print(trade_df.describe(include='max_positions')) \ No newline at end of file diff --git a/v2realbot/ENTRY_KLARA.py b/v2realbot/ENTRY_KLARA.py new file mode 100644 index 0000000..64a520d --- /dev/null +++ b/v2realbot/ENTRY_KLARA.py @@ -0,0 +1,594 @@ +import os,sys +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from v2realbot.strategy.base import StrategyState +from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL +from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType +from v2realbot.indicators.indicators import ema +from v2realbot.indicators.oscillators import rsi +from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five, is_open_rush, is_close_rush, eval_cond_dict +from datetime import datetime +#from icecream import install, ic +#from rich import print +from threading import Event +from msgpack import packb, unpackb +import asyncio +import os +from traceback import format_exc +import inspect + +print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +"""" +MYSELL, CBAR + +Rychloobratka KLARA + +- profit 0.005 +- buy signal nejspis RSI, cilem co nejvic obchodu - rychle ven + + + +""" +stratvars = AttributeDict(maxpozic = 400, + def_mode_from = 200, + chunk = 10, + MA = 2, + Trend = 2, + profit = 0.02, + def_profit = 0.01, + lastbuyindex=-6, + pendingbuys={}, + limitka = None, + limitka_price = None, + jevylozeno=0, + vykladka=5, + curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01], + curve_def = [0.02, 0.02, 0.02, 0, 0, 0.02, 0, 0, 0, 0.02], + blockbuy = 0, + ticks2reset = 0.04, + consolidation_bar_count = 10, + slope_lookback = 300, + lookback_offset = 20, + minimum_slope = -0.05, + first_buy_market = False + ) +##toto rozparsovat a strategii spustit stejne jako v main +toml_string = """ +[[strategies]] +name = "V1 na BAC" +symbol = "BAC" +script = "ENTRY_backtest_strategyVykladaci" +class = "StrategyOrderLimitVykladaci" +open_rush = 0 +close_rush = 0 +[strategies.stratvars] +maxpozic = 200 +chunk = 10 +MA = 6 +Trend = 5 +profit = 0.02 +lastbuyindex=-6 +pendingbuys={} +limitka = "None" +jevylozeno=0 +vykladka=5 +curve = [0.01, 0.01, 0.01,0.01, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01] +blockbuy = 0 +ticks2reset = 0.04 +[[strategies.add_data]] +symbol="BAC" +rectype="bar" +timeframe=5 +update_ltp=true +align="round" +mintick=0 +minsize=100 +exthours=false +""" + +def next(data, state: StrategyState): + print(10*"*","NEXT START",10*"*") + #ic(state.avgp, state.positions) + #ic(state.vars) + #ic(data) + + # + def is_defensive_mode(): + akt_pozic = int(state.positions) + max_pozic = int(state.vars.maxpozic) + def_mode_from = safe_get(state.vars, "def_mode_from",max_pozic/2) + if akt_pozic >= int(def_mode_from): + #state.ilog(e=f"DEFENSIVE mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) + return True + else: + #state.ilog(e=f"STANDARD mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) + return False + + def get_limitka_price(): + def_profit = safe_get(state.vars, "def_profit",state.vars.profit) + cena = float(state.avgp) + #v MYSELL hrajeme i na 3 desetinna cisla - TBD mozna hrat jen na 5ky (0.125, 0.130, 0.135 atp.) + if is_defensive_mode(): + return price2dec(cena+get_tick(cena,float(def_profit)),3) + else: + return price2dec(cena+get_tick(cena,float(state.vars.profit)),3) + + def consolidation(): + ##CONSOLIDATION PART - moved here, musí být před nákupem, jinak to dělalo nepořádek v pendingbuys + #docasne zkusime konzolidovat i kdyz neni vylozeno (aby se srovnala limitka ve vsech situacich) + if state.vars.jevylozeno == 1 or 1==1: + ##CONSOLIDATION PART kazdy Nty bar dle nastaveni + if int(data["index"])%int(state.vars.consolidation_bar_count) == 0: + print("***CONSOLIDATION ENTRY***") + state.ilog(e="CONSOLIDATION ENTRY ***") + + orderlist = state.interface.get_open_orders(symbol=state.symbol, side=None) + #pro jistotu jeste dotahneme aktualni pozice + state.avgp, state.positions = state.interface.pos() + + #print(orderlist) + pendingbuys_new = {} + #zaciname s cistym stitem + state.vars.limitka = None + state.vars.limitka_price = None + for o in orderlist: + if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT: + pendingbuys_new[str(o.id)]=float(o.limit_price) + + if pendingbuys_new != state.vars.pendingbuys: + state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys) + print("ROZDILNA PENDINGBUYS přepsána") + print("OLD",state.vars.pendingbuys) + state.vars.pendingbuys = unpackb(packb(pendingbuys_new)) + print("NEW", state.vars.pendingbuys) + else: + print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys) + state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys) + print("OLD jevylozeno", state.vars.jevylozeno) + if len(state.vars.pendingbuys) > 0: + state.vars.jevylozeno = 1 + else: + state.vars.jevylozeno = 0 + print("NEW jevylozeno", state.vars.jevylozeno) + state.ilog(e="Nove jevylozeno", msg=state.vars.jevylozeno) + + print("***CONSOLIDATION EXIT***") + state.ilog(e="CONSOLIDATION EXIT ***") + else: + state.ilog(e="No time for consolidation", msg=data["index"]) + print("no time for consolidation", data["index"]) + #mozna presunout o level vys + def vyloz(): + ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci + #curve = [0.01, 0.01, 0, 0, 0.01, 0, 0, 0, 0.02, 0, 0, 0, 0.03, 0,0,0,0,0, 0.02, 0,0,0,0,0,0, 0.02] + curve = state.vars.curve + ##defenzivni krivka pro + curve_def = state.vars.curve_def + #vykladani po 5ti kusech, když zbývají 2 a méně, tak děláme nový výklad + vykladka = state.vars.vykladka + #kolik muzu max vylozit + kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk)) + akt_pozic = int(state.positions) + max_pozic = int(state.vars.maxpozic) + + if akt_pozic >= max_pozic: + state.ilog(e="MAX pozic reached, cannot vyklad") + return + + #mame polovinu a vic vylozeno, pouzivame defenzicni krivku + if is_defensive_mode(): + state.ilog(e="DEF: Pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def) + curve = curve_def + #zaroven docasne menime ticks2reset na defenzivni 0.06 + state.vars.ticks2reset = 0.06 + state.ilog(e="DEF: Menime tick2reset na 0.06", ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup) + else: + #vracime zpet, pokud bylo zmeneno + if state.vars.ticks2reset != state.vars.ticks2reset_backup: + state.vars.ticks2reset = state.vars.ticks2reset_backup + state.ilog(e="DEF: Menime tick2reset zpet na"+str(state.vars.ticks2reset), ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup) + + if kolikmuzu < vykladka: vykladka = kolikmuzu + + if len(curve) < vykladka: + vykladka = len(curve) + qty = int(state.vars.chunk) + last_price = price2dec(state.interface.get_last_price(state.symbol)) + #profit = float(state.vars.profit) + price = last_price + state.ilog(e="BUY Vykladame", msg=f"first price {price=} {vykladka=}", curve=curve, ema=state.indicators.ema[-1], trend=state.vars.Trend, price=price, vykladka=vykladka) + ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci + + ##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order + if safe_get(state.vars, "first_buy_market") == True: + #pri defenzivnim rezimu pouzivame vzdy LIMIT order + if is_defensive_mode(): + state.ilog(e="DEF mode on, odesilame jako prvni limitku") + state.buy_l(price=price, size=qty) + else: + state.ilog(e="Posilame jako prvni MARKET order") + state.buy(size=qty) + else: + state.buy_l(price=price, size=qty) + print("prvni limitka na aktuální cenu. Další podle křivky", price, qty) + for i in range(0,vykladka-1): + price = price2dec(float(price - get_tick(price, curve[i]))) + if price == last_price: + qty = qty + int(state.vars.chunk) + else: + state.buy_l(price=price, size=qty) + #print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty) + qty = int(state.vars.chunk) + last_price = price + state.vars.blockbuy = 1 + state.vars.jevylozeno = 1 + state.vars.last_buysignal_index = data['index'] + + def eval_sell(): + """" + TBD + Když je RSI nahoře tak neprodávat, dokud 1) RSI neprestane stoupat 2)nedosahne to nad im not greedy limit + """ + ##mame pozice + ##aktualni cena je vetsi nebo rovna cene limitky + #muzeme zde jet i na pulcenty + curr_price = float(data['close']) + state.ilog(e="Eval SELL", price=curr_price, pos=state.positions, avgp=state.avgp, sell_in_progress=state.vars.sell_in_progress) + if int(state.positions) > 0 and float(state.avgp)>0 and state.vars.sell_in_progress is False: + goal_price = get_limitka_price() + state.ilog(e=f"Goal price {goal_price}") + if curr_price>=goal_price: + + #TODO cekat az slope prestane intenzivn erust, necekat az na klesani + #TODO mozna cekat na nejaky signal RSI + #TODO pripadne pokud dosahne TGTBB prodat ihned + + #OPTIMALIZACE pri stoupajícím angle + if sell_protection_enabled() is False: + state.interface.sell(size=state.positions) + state.vars.sell_in_progress = True + state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress) + + def populate_ema_indicator(): + #BAR EMA INDICATOR - + #plnime MAcko - nyni posilame jen N poslednich hodnot + #zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu + try: + ma = int(state.vars.MA) + #poslednich ma hodnot + source = state.bars.close[-ma:] #state.bars.vwap + ema_value = ema(source, ma) + + ##pokus MACKO zakrouhlit na tri desetina a petku + state.indicators.ema[-1]=round2five(ema_value[-1]) + ##state.indicators.ema[-1]=trunc(ema_value[-1],3) + #state.ilog(e=f"EMA {state.indicators.ema[-1]}", ema_last=state.indicators.ema[-6:]) + except Exception as e: + state.ilog(e="EMA nechavame 0", message=str(e)+format_exc()) + #state.indicators.ema[-1]=(0) + #evaluate buy signal + #consolidation + + def populate_slope_indicator(): + #SLOPE INDICATOR + #úhel stoupání a klesání vyjádřený mezi -1 až 1 + #pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback. + #obsahuje statický indikátor (angle) pro vizualizaci + try: + slope = 99 + slope_lookback = int(state.vars.slope_lookback) + minimum_slope = float(state.vars.minimum_slope) + lookback_offset = int(state.vars.lookback_offset) + + if len(state.bars.close) > (slope_lookback + lookback_offset): + array_od = slope_lookback + lookback_offset + array_do = slope_lookback + lookbackprice_array = state.bars.vwap[-array_od:-array_do] + #obycejný prumer hodnot + lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3) + + #výpočet úhlu - a jeho normalizace + slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100 + slope = round(slope, 4) + state.indicators.slope[-1]=slope + + #angle je ze slope + state.statinds.angle = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=state.bars.time[-slope_lookback], lookbackprice=lookbackprice, minimum_slope=minimum_slope, maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20)) + + #slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA + slope_MA_length = 5 + source = state.indicators.slope[-slope_MA_length:] + slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap + slopeMA = slopeMAseries[-1] + state.indicators.slopeMA[-1]=slopeMA + + state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:], last_slopesMA=state.indicators.slopeMA[-10:]) + + #dale pracujeme s timto MAckovanym slope + slope = slopeMA + else: + #pokud plnime historii musime ji plnit od zacatku, vsehcny idenitifkatory maji spolecny time + #kvuli spravnemu zobrazovani na gui + #state.indicators.slopeMA[-1]=0 + #state.indicators.slopeMA.append(0) + state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA) + except Exception as e: + print("Exception in NEXT Slope Indicator section", str(e)) + state.ilog(e="EXCEPTION", msg="Exception in Slope Indicator section" + str(e) + format_exc()) + + def populate_rsi_indicator(): + #RSI14 INDICATOR + try: + rsi_length = int(safe_get(state.vars, "rsi_length",14)) + source = state.bars.close #[-rsi_length:] #state.bars.vwap + rsi_res = rsi(source, rsi_length) + rsi_value = trunc(rsi_res[-1],3) + state.indicators.RSI14[-1]=rsi_value + #state.ilog(e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:]) + except Exception as e: + state.ilog(e=f"RSI {rsi_length=} necháváme 0", message=str(e)+format_exc()) + #state.indicators.RSI14[-1]=0 + + def populate_cbar_rsi_indicator(): + #CBAR RSI indicator + try: + crsi_length = int(safe_get(state.vars, "crsi_length",14)) + source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap + crsi_res = rsi(source, crsi_length) + crsi_value = trunc(crsi_res[-1],3) + state.cbar_indicators.CRSI[-1]=crsi_value + #state.ilog(e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:]) + except Exception as e: + state.ilog(e=f"CRSI {crsi_length=} necháváme 0", message=str(e)+format_exc()) + #state.indicators.RSI14[-1]=0 + + def slope_too_low(): + return state.indicators.slopeMA[-1] < float(state.vars.minimum_slope) + + def slope_too_high(): + return state.indicators.slopeMA[-1] > float(safe_get(state.vars, "bigwave_slope_above",0.20)) + + #resetujeme, kdyz 1) je aktivni buy protection 2) kdyz to ujede + #TODO mozna tick2reset spoustet jednou za X opakovani + def pendingbuys_optimalization(): + if len(state.vars.pendingbuys)>0: + if buy_protection_enabled(): + #state.ilog(e="PENDINGBUYS reset", message=inspect.currentframe().f_code.co_name) + res = asyncio.run(state.cancel_pending_buys()) + state.ilog(e="CANCEL pendingbuyes", pb=state.vars.pendingbuys, res=res) + else: + #pokud mame vylozeno a cena je vetsi nez tick2reset + maxprice = max(state.vars.pendingbuys.values()) + if state.interface.get_last_price(state.symbol) > float(maxprice) + get_tick(maxprice, float(state.vars.ticks2reset)): + res = asyncio.run(state.cancel_pending_buys()) + state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys) + + #PENDING BUYS SPENT - PART + #pokud mame vylozeno a pendingbuys se vyklepou a + # 1 vykladame idned znovu + # vyloz() + # 2 nebo - počkat zase na signál a pokračovat dál + # state.vars.blockbuy = 0 + # state.vars.jevylozeno = 0 + # 3 nebo - počkat na signál s enablovaným lastbuy indexem (tzn. počká nutně ještě pár barů) + #podle BT vyhodnejsi vylozit ihned + if len(state.vars.pendingbuys) == 0: + state.vars.blockbuy = 0 + state.vars.jevylozeno = 0 + state.ilog(e="PB prazdne nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno) + + ##kdy nesmí být žádné nákupní objednávky - zruší se + def buy_protection_enabled(): + dont_buy_when = dict(AND=dict(), OR=dict()) + ##add conditions here + dont_buy_when['rsi_too_high'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) + dont_buy_when['slope_too_low'] = slope_too_low() + + result, cond_met = eval_cond_dict(dont_buy_when) + if result: + state.ilog(e=f"BUY_PROTECTION {cond_met}") + return result + + def sell_protection_enabled(): + dont_sell_when = dict(AND=dict(), OR=dict()) + ##add conditions here + + #IDENTIFIKOVAce rustoveho MOMENTA - pokud je momentum, tak prodávat později + + #pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3) + + #toto docasne pryc dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4) + dont_sell_when['AND']['slopeMA_rising'] = isrising(state.indicators.slopeMA,2) + dont_sell_when['AND']['rsi_not_falling'] = not isfalling(state.indicators.RSI14,3) + #dont_sell_when['rsi_dont_buy'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) + + result, conditions_met = eval_cond_dict(dont_sell_when) + if result: + state.ilog(e=f"SELL_PROTECTION {conditions_met} enabled") + return result + + #preconditions and conditions of BUY SIGNAL + def buy_conditions_met(): + #preconditions + dont_buy_when = dict(AND=dict(), OR=dict()) + + + if safe_get(state.vars, "buy_only_on_confirmed",True): + dont_buy_when['bar_not_confirmed'] = (data['confirmed'] == 0) + #od posledniho vylozeni musi ubehnout N baru + dont_buy_when['last_buy_offset_too_soon'] = data['index'] < (state.vars.last_buysignal_index + safe_get(state.vars, "lastbuy_offset",3)) + dont_buy_when['blockbuy_active'] = (state.vars.blockbuy == 1) + dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1) + dont_buy_when['rsi_too_high'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) + dont_buy_when['slope_too_low'] = slope_too_low() + dont_buy_when['open_rush'] = is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "open_rush",0)) + dont_buy_when['close_rush'] = is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "close_rush",0)) + dont_buy_when['rsi_is_zero'] = (state.indicators.RSI14[-1] == 0) + + #testing preconditions + result, cond_met = eval_cond_dict(dont_buy_when) + if result: + state.ilog(e=f"BUY precondition not met {cond_met}") + return False + + #conditions - bud samostatne nebo v groupe - ty musi platit dohromady + buy_cond = dict(AND=dict(), OR=dict()) + ##add buy conditions here + #cond groups ["AND"] + #cond groups ["OR"] + #no cond group - takes first + #TEST BUY SIGNALu z cbartick_price - 3klesave za sebou + #buy_cond['tick_price_falling_trend'] = isfalling(state.cbar_indicators.tick_price,state.vars.Trend) + + #slopeMA jde dolu, rsi jde nahoru + #buy mame kazdy potvrzeny, tzn. rsi falling muze byt jen 2 + + #buy_cond['AND']['slopeMA_falling'] = isfalling(state.indicators.slopeMA,3) + #buy_cond['AND']['rsi_is_rising'] = isrising(state.indicators.RSI14,2) + #buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40) + + #puvodni buy conditiony RSI pod + EMA klesajici + #buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40) + #buy_cond["AND"]["ema_trend_is_falling"] = isfalling(state.indicators.ema,state.vars.Trend) + + #pouze RSI nizke a RSI klesa + buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40) + buy_cond["AND"]["rsi_is_falling"] = isfalling(state.indicators.RSI14,state.vars.Trend) + + #buy_cond['crsi_below_crsi_buy_limit'] = state.cbar_indicators.CRSI[-1] < safe_get(state.vars, "crsi_buy_signal_below",30) + + #slopME klesa a RSI začalo stoupat + # buy_cond["AND"]["rsi_is_rising2"] = isrising(state.indicators.RSI14,2) + # buy_cond['AND']['slopeMA_falling_Trend'] = isfalling(state.indicators.slopeMA,state.vars.Trend) + # buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40) + + + #zkusit jako doplnkovy BUY SIGNAL 3 klesavy cbar RSI pripadne TICK PRICE + + result, conditions_met = eval_cond_dict(buy_cond) + if result: + state.ilog(e=f"BUY SIGNAL {conditions_met}") + return result + + def eval_buy(): + if buy_conditions_met(): + vyloz() + + def populate_cbar_tick_price_indicator(): + try: + #pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty + # if tick_delta_volume == 0: + # state.indicators.tick_price[-1] = state.indicators.tick_price[-2] + # state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2] + # else: + + tick_price = round2five(data['close']) + tick_delta_volume = data['volume'] - state.vars.last_tick_volume + + #docasne dame pryc volume deltu a davame absolutni cislo + state.cbar_indicators.tick_price[-1] = tick_price + state.cbar_indicators.tick_volume[-1] = tick_delta_volume + except: + pass + + state.ilog(e=f"TICK PRICE {tick_price} VOLUME {tick_delta_volume} {conf_bar=}", prev_price=state.vars.last_tick_price, prev_volume=state.vars.last_tick_volume) + + state.vars.last_tick_price = tick_price + state.vars.last_tick_volume = data['volume'] + + def get_last_ind_vals(): + last_ind_vals = {} + #print(state.indicators.items()) + for key in state.indicators: + if key != 'time': + last_ind_vals[key] = state.indicators[key][-5:] + + for key in state.cbar_indicators: + if key != 'time': + last_ind_vals[key] = state.cbar_indicators[key][-5:] + return last_ind_vals + + conf_bar = data['confirmed'] + last_update_delta = round((float(data['updated']) - state.vars.last_update_time),6) if state.vars.last_update_time != 0 else 0 + state.vars.last_update_time = float(data['updated']) + state.ilog(e=f"---{data['index']}-{conf_bar}--delta:{last_update_delta}") + + #kroky pro CONFIRMED BAR only + if conf_bar == 1: + #logika pouze pro potvrzeny bar + state.ilog(e="BAR potvrzeny") + + + #pri potvrzem CBARu nulujeme counter volume pro tick based indicator + state.vars.last_tick_volume = 0 + state.vars.next_new = 1 + + #kroky pro CONTINOUS TICKS only + else: + #CBAR INDICATOR pro tick price a deltu VOLUME + populate_cbar_tick_price_indicator() + populate_cbar_rsi_indicator() + + #SPOLECNA LOGIKA - bar indikatory muzeme populovat kazdy tick (dobre pro RT GUI), ale uklada se stejne az pri confirmu + + + populate_ema_indicator() + populate_slope_indicator() + populate_rsi_indicator() + eval_sell() + consolidation() + + #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru + lp = state.interface.get_last_price(symbol=state.symbol) + state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars) + state.ilog(e="Indikatory", msg=str(get_last_ind_vals())) + + eval_buy() + pendingbuys_optimalization() + +def init(state: StrategyState): + #place to declare new vars + print("INIT v main",state.name) + + state.vars['sell_in_progress'] = False + state.vars.last_tick_price = 0 + state.vars.last_tick_volume = 0 + state.vars.next_new = 0 + state.vars.last_buysignal_index = 0 + state.vars.last_update_time = 0 + #state.cbar_indicators['ivwap'] = [] + state.cbar_indicators['tick_price'] = [] + state.cbar_indicators['tick_volume'] = [] + state.cbar_indicators['CRSI'] = [] + state.indicators['ema'] = [] + state.indicators['slope'] = [] + state.indicators['slopeMA'] = [] + state.indicators['RSI14'] = [] + #static indicators - those not series based + state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"], maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20)) + state.vars["ticks2reset_backup"] = state.vars.ticks2reset + +def main(): + name = os.path.basename(__file__) + se = Event() + pe = Event() + s = StrategyOrderLimitVykladaciNormalizedMYSELL(name = name, symbol = "BAC", account=Account.ACCOUNT1, next=next, init=init, stratvars=stratvars, open_rush=10, close_rush=0, pe=pe, se=se, ilog_save=True) + s.set_mode(mode = Mode.BT, + debug = False, + start = datetime(2023, 4, 14, 10, 42, 0, 0, tzinfo=zoneNY), + end = datetime(2023, 4, 14, 14, 35, 0, 0, tzinfo=zoneNY), + cash=100000) + + #na sekundovem baru nezaokrouhlovat MAcko + s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=2,minsize=100,update_ltp=True,align=StartBarAlign.ROUND,mintick=0, exthours=False) + #s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0) + + s.start() + print("zastavujeme") + +if __name__ == "__main__": + main() + + + + + \ No newline at end of file diff --git a/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py b/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py index eb6a0a9..eca1f9f 100644 --- a/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py +++ b/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py @@ -117,6 +117,18 @@ def next(data, state: StrategyState): else: return price2dec(cena+get_tick(cena,float(state.vars.profit)),3) + def optimize_qty_multiplier(): + akt_pozic = int(state.positions)/int(state.vars.chunk) + multiplier = 1 + + #zatim jednoduse pokud je akt. pozice 1 nebo 3 chunky (<4) tak zdvojnásubuju + #aneb druhy a treti nakup + if akt_pozic > 0 and akt_pozic < 4: + multiplier = safe_get(state.vars, "market_buy_multiplier", 2) + state.ilog(e=f"BUY MULTIPLIER: {multiplier}") + return multiplier + + def consolidation(): ##CONSOLIDATION PART - moved here, musí být před nákupem, jinak to dělalo nepořádek v pendingbuys #docasne zkusime konzolidovat i kdyz neni vylozeno (aby se srovnala limitka ve vsech situacich) @@ -205,13 +217,14 @@ def next(data, state: StrategyState): ##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order if safe_get(state.vars, "first_buy_market") == True: - #pri defenzivnim rezimu pouzivame vzdy LIMIT order - if is_defensive_mode(): + #pri defenzivnim rezimu pouzijeme LIMIT nebo MARKET podle nastaveni + if is_defensive_mode() and safe_get(state.vars, "first_buy_market_def_mode", False) is False: state.ilog(e="DEF mode on, odesilame jako prvni limitku") state.buy_l(price=price, size=qty) else: state.ilog(e="Posilame jako prvni MARKET order") - state.buy(size=qty) + #market size optimalization based on conditions + state.buy(size=optimize_qty_multiplier()*qty) else: state.buy_l(price=price, size=qty) print("prvni limitka na aktuální cenu. Další podle křivky", price, qty) @@ -241,6 +254,8 @@ def next(data, state: StrategyState): if int(state.positions) > 0 and float(state.avgp)>0 and state.vars.sell_in_progress is False: goal_price = get_limitka_price() state.ilog(e=f"Goal price {goal_price}") + + #pokud je cena vyssi if curr_price>=goal_price: #TODO cekat az slope prestane intenzivn erust, necekat az na klesani @@ -252,6 +267,54 @@ def next(data, state: StrategyState): state.interface.sell(size=state.positions) state.vars.sell_in_progress = True state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress) + #pokud je cena nizsi, testujeme REVERSE POZITION PROTECTION + else: + pass + #reverse_position() + + # def reverse_position(): + # """" + # Reverse position - ochrana pred vetsim klesanim + # - proda kdyz je splnena podminka + # - nakoupi opet ve stejnem mnozstvi, kdyz je splnena podminka + + # required STRATVARS: + # reverse_position_slope = -0.9 + # reverse_position_on_confirmed_only = true + # reverse_position_waiting_amount = 0 + # """"" + # #reverse position preconditions + # dont_do_reverse_when = {} + + # dont_do_reverse_when['reverse_position_waiting_amount_not_0'] = (state.vars.reverse_position_waiting_amount != 0) + + # result, conditions_met = eval_cond_dict(dont_do_reverse_when) + # if result: + # state.ilog(e=f"REVERSE_PRECOND PROTECTION {conditions_met}") + # return result + + + # #reverse position for + # confirmrequried = safe_get(state.vars, "reverse_position_on_confirmed_only", True) + # if (confirmrequried and data['confirmed'] == 1) or confirmrequried is False: + # #check reverse position + # state.ilog(e="REVERSE POSITION check - GO") + # else: + # #not time for reverse position + # state.ilog(e="REVERSE POSITION check - NO TIME") + + # #predpokladame, ze uz byly testovany pozice a mame je if int(state.positions) > 0 and float(state.avgp)>0 + # if state.indicators.slopeMA[-1] < float(safe_get(state.vars, "reverse_position_slope", -0.10)): + # state.interface.sell(size=state.positions) + # state.vars.sell_in_progress = True + # state.ilog(e=f"REV POS market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress) + # state.vars.rev_position_waiting_amount = + + + + + + def populate_ema_indicator(): #BAR EMA INDICATOR - @@ -428,6 +491,7 @@ def next(data, state: StrategyState): dont_buy_when['open_rush'] = is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "open_rush",0)) dont_buy_when['close_rush'] = is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "close_rush",0)) dont_buy_when['rsi_is_zero'] = (state.indicators.RSI14[-1] == 0) + dont_buy_when['reverse_position_waiting_amount_not_0'] = (state.vars.reverse_position_waiting_amount != 0) #testing preconditions result, cond_met = eval_cond_dict(dont_buy_when) @@ -560,6 +624,7 @@ def init(state: StrategyState): state.vars.next_new = 0 state.vars.last_buysignal_index = 0 state.vars.last_update_time = 0 + state.vars.reverse_position_waiting_amount = 0 #state.cbar_indicators['ivwap'] = [] state.cbar_indicators['tick_price'] = [] state.cbar_indicators['tick_volume'] = [] diff --git a/v2realbot/common/__pycache__/model.cpython-310.pyc b/v2realbot/common/__pycache__/model.cpython-310.pyc index 59c7cad..1d6a7e5 100644 Binary files a/v2realbot/common/__pycache__/model.cpython-310.pyc and b/v2realbot/common/__pycache__/model.cpython-310.pyc differ diff --git a/v2realbot/common/model.py b/v2realbot/common/model.py index 1887059..43cf68a 100644 --- a/v2realbot/common/model.py +++ b/v2realbot/common/model.py @@ -186,7 +186,7 @@ class RunArchive(BaseModel): trade_count: int = 0 end_positions: int = 0 end_positions_avgp: float = 0 - open_orders: int = 0 + open_orders: Union[dict, int] = None #Contains archive of running strategies (runner) - detail data class RunArchiveDetail(BaseModel): diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 8c91721..c99ca90 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -5,8 +5,8 @@ from alpaca.data.historical import StockHistoricalDataClient from alpaca.data.requests import StockTradesRequest, StockBarsRequest from alpaca.data.enums import DataFeed from alpaca.data.timeframe import TimeFrame -from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account -from v2realbot.common.model import StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveDetail, RunArchiveChange, Bar +from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide +from v2realbot.common.model import StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram from v2realbot.utils.ilog import delete_logs from datetime import datetime @@ -416,50 +416,48 @@ def get_trade_history(symbol: str, timestamp_from: float, timestamp_to:float): except Exception as e: return (-2, f"problem {e}") - - def populate_metrics_output_directory(strat: StrategyInstance): """ WIP Spocte zakladni metriky pred ulozenim do archivu + + 1) zatim jen max pozice """ - #open_orders to dataset - oo_dict = AttributeDict(orderid=[],submitted_at=[],symbol=[],side=[],order_type=[],qty=[],limit_price=[],status=[]) - for t in strat.open_orders: - oo_dict.orderid.append(str(t.id)) - oo_dict.submitted_at.append(t.submitted_at) - oo_dict.symbol.append(t.symbol) - oo_dict.side.append(t.side) - oo_dict.qty.append(t.qty) - oo_dict.order_type.append(t.order_type) - oo_dict.limit_price.append(t.limit_price) - oo_dict.status.append(t.status) - open_orders_df = pd.DataFrame(oo_dict) - open_orders_df = open_orders_df.set_index('submitted_at', drop=False) + tradeList = strat.state.tradeList - #trades to dataset trade_dict = AttributeDict(orderid=[],timestamp=[],symbol=[],side=[],order_type=[],qty=[],price=[],position_qty=[],value=[],cash=[],pos_avg_price=[]) - for t in strat.trades: - trade_dict.orderid.append(str(t.order.id)) - trade_dict.timestamp.append(t.timestamp) - trade_dict.symbol.append(t.order.symbol) - trade_dict.side.append(t.order.side) - trade_dict.qty.append(t.qty) - trade_dict.price.append(t.price) - trade_dict.position_qty.append(t.position_qty) - trade_dict.value.append(t.value) - trade_dict.cash.append(t.cash) - trade_dict.order_type.append(t.order.order_type) - trade_dict.pos_avg_price.append(t.pos_avg_price) + for t in tradeList: + if t.event == TradeEvent.FILL: + trade_dict.orderid.append(str(t.order.id)) + trade_dict.timestamp.append(t.timestamp) + trade_dict.symbol.append(t.order.symbol) + trade_dict.side.append(t.order.side) + trade_dict.qty.append(t.qty) + trade_dict.price.append(t.price) + trade_dict.position_qty.append(t.position_qty) + trade_dict.value.append(t.value) + trade_dict.cash.append(t.cash) + trade_dict.order_type.append(t.order.order_type) + trade_dict.pos_avg_price.append(t.pos_avg_price) trade_df = pd.DataFrame(trade_dict) trade_df = trade_df.set_index('timestamp',drop=False) + #max positions- tzn. count max quantity ze sell fill orderu + #nepocita otevrene objednavky + max_positions = trade_df.groupby('side')['qty'].value_counts().reset_index(name='count').sort_values(['qty'], ascending=False) + max_positions = max_positions[max_positions['side'] == OrderSide.SELL] + max_positions = max_positions.drop(columns=['side'], axis=1) + + #filt = max_positions['side'] == 'OrderSide.BUY' + res = dict(zip(max_positions['qty'], max_positions['count'])) + + return res #archives runner and details def archive_runner(runner: Runner, strat: StrategyInstance): - #results_metrics = dict() + results_metrics = dict() print("inside archive_runner") try: if strat.bt is not None: @@ -481,8 +479,8 @@ def archive_runner(runner: Runner, strat: StrategyInstance): #populate result metrics dictionary (max drawdown etc.) #list of maximum positions (2000 2x, 1800 x 1, 900 x 1, 100 x 20) #list of most profitable trades (pos,avgp + cena) - #nejspis prevedeni na dataset a report nad datasetem - #results_metrics = populate_metrics(strat) + #file pro vyvoj: ouptut_metriky_tradeList.py + results_metrics = populate_metrics_output_directory(strat) runArchive: RunArchive = RunArchive(id = runner.id, strat_id = runner.strat_id, @@ -503,7 +501,7 @@ def archive_runner(runner: Runner, strat: StrategyInstance): trade_count=len(strat.state.tradeList), end_positions=strat.state.positions, end_positions_avgp=round(float(strat.state.avgp),3), - open_orders=9999 + open_orders=results_metrics ) #flatten indicators from numpy array diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 39a253f..e2a6114 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -194,7 +194,7 @@ pos pos_avgp json - open + metrics @@ -239,6 +239,10 @@ +
+ + +
@@ -417,7 +421,7 @@