Skip to content

Instantly share code, notes, and snippets.

@lawrence910426
Created June 16, 2024 08:39
Show Gist options
  • Save lawrence910426/048767d3f13aee67f56db779fa905a25 to your computer and use it in GitHub Desktop.
Save lawrence910426/048767d3f13aee67f56db779fa905a25 to your computer and use it in GitHub Desktop.
import time
import logging
import math
import os
import contextlib
import concurrent
import math
from decimal import *
from notify import Notify
import shioaji as sj
class Automata:
def __init__(self, sj_api, observe_id, trade_id):
self.sj_api = sj_api
self.observe_id = observe_id
self.trade_id = trade_id
self.observed_bulk_long, self.observed_bulk_short = False, False
self.order, self.entry_time = None, 0
self.bid_price, self.ask_price = None, None
self.last_update = 0
self.state = "INIT"
self.previous_state = self.state
self.market_orders, self.limit_down = 0, 0
def loop(self):
if self.state == "INIT":
"""
The automata is initialized and everything is resetted.
"""
self.state = "WAIT_BULK_ORDER"
elif self.state == "WAIT_BULK_ORDER":
"""
Waiting for bulk order to arrive.
"""
if self.observed_bulk_long:
self.state = "PLACE_LONG_ORDER"
self.observed_bulk_long = False
if self.observed_bulk_short:
self.state = "PLACE_SHORT_ORDER"
self.observed_bulk_short = False
elif self.state == "PLACE_LONG_ORDER":
"""
Place a long order on trading instrument.
"""
if self.ask_price is not None:
self.order = self.place_order(
self.ask_price, 1, "BUY"
)
Notify.notify(f"Placed a buy order on {self.trade_id}")
self.entry_time = time.time()
self.state = "WAIT_DEAL"
elif self.state == "PLACE_SHORT_ORDER":
"""
Place a short order on trading instrument.
"""
if self.bid_price is not None:
self.order = self.place_order(
self.bid_price, 1, "SELL"
)
Notify.notify(f"Placed a sell order on {self.trade_id}")
self.entry_time = time.time()
self.state = "WAIT_DEAL"
elif self.state == "WAIT_DEAL":
"""
Wait until our order is dealt
"""
if self.order.status.status in [sj.constant.Status.Inactive]:
self.sj_api.update_status(trade=self.order)
if self.order.status.status in [sj.constant.Status.Filled]:
self.state = "BUILT"
if self.entry_time + 5 < time.time():
self.state = "CANCEL_ORDER"
elif self.state == "CANCEL_ORDER":
"""
Cancel our placed order.
"""
self.sj_api.cancel_order(self.order)
self.sj_api.update_status(trade=self.order)
status = self.order.status.status
if status in [sj.constant.Status.Filled]:
self.state = "BUILT"
else:
self.state = "INIT"
elif self.state == "BUILT":
"""
Our order is filled. Show a notification.
"""
Notify.notify(f"Position is built on {self.trade_id}")
self.state = "IDLE"
elif self.state == "IDLE":
"""
Idle state. Nothing to do.
"""
pass
if self.previous_state != self.state:
logging.warning(f"State changed from {self.previous_state} to {self.state}")
self.previous_state = self.state
def place_order(self, price, size, side):
logging.info(f"Start placing order on {self.trade_id}")
order = self.sj_api.Order(
price=price,
quantity=size,
action=sj.constant.Action.Buy if side == "BUY" else sj.constant.Action.Sell,
price_type=sj.constant.StockPriceType.LMT,
order_type=sj.constant.OrderType.ROD,
order_lot=sj.constant.StockOrderLot.Common,
account=self.sj_api.stock_account,
daytrade_short=False if side == "BUY" else True
)
logging.warning(f"Placing order: {order}")
result = self.sj_api.place_order(self.sj_api.Contracts.Stocks[self.trade_id], order, timeout=0)
logging.warning(f"Place order result: {result}")
return result
def handle_quote_message(self, exchange, quote):
# Ignore the signal if simtrade
if quote["simtrade"] == 1:
return
timestamp = quote["datetime"].timestamp() * (10 ** 6) # In microseconds
if timestamp < self.last_update:
return
self.last_update = timestamp
if quote["code"] == self.trade_id:
self.bid_price = quote.bid_price[0]
self.ask_price = quote.ask_price[0]
if quote["code"] == self.observe_id:
if quote["volume"] >= 100:
if quote["tick_type"] == 1:
self.observed_bulk_long = True
if quote["tick_type"] == 2:
self.observed_bulk_short = True
# To use
# 1. automata = Automata(...)
# 2. while True: automata.loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment