From 3a421ceb349e77323e18f08df28c5fafbdeae4e1 Mon Sep 17 00:00:00 2001 From: Manuel Plonski Date: Sun, 22 Jan 2023 14:46:05 +0100 Subject: [PATCH] adding some basic exchange --- econ/__pycache__/exchange.cpython-38.pyc | Bin 0 -> 4132 bytes econ/business.py | 3 +- econ/exchange.py | 172 +++++++++++++++++++++++ main.py | 13 ++ requirements.txt | 1 + 5 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 econ/__pycache__/exchange.cpython-38.pyc create mode 100644 econ/exchange.py create mode 100644 requirements.txt diff --git a/econ/__pycache__/exchange.cpython-38.pyc b/econ/__pycache__/exchange.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..539332d49053b722c61bcf52bfa25c70b358fa7a GIT binary patch literal 4132 zcmb_fTW{mW6`tWulq}QoWxe)p+OSzPiIT!-iy~bF+o0WTHf@o0gE;$8!2!YLjBLsx zR;$n&pEtUQVbL*N`a%9GiPq!eCNXF>+2l` z&tHD^_h@{Vv43J?@iC$CYk0E*C(>Oi(I6a9|Sy)H0kcIt)3i0ocN=Ox< z{^HYY;~S7lHsG)oL-2tq3}Jr9g(d9QuodBm)@wGfr9)Czv_aYu9kB*dS9HZX{I`WC zHsHS_9l0iY-x*?4Y=K@^Y>OR`uY>ds%(*M>g4B~6Vh>vT;vTem!hnO_FWis6j!wh$ zM9v;`e0Uy*SseLKCP^|8v3}*ts{4R?5Bt1ul+;s|MttE|SU2E(0&n&hikRgrC`+!5 zZ?R>P%%ajhL5V~47L_iQZ7Ms09kFYE*k3DJVH8cKsV*FuMQZYuLi`GIoXBExf&d4V zLXd>#g+rpO*pOe#XsV?MG~Pv4>*|RP$HBRZBU!8^p*oW~P@$Fs_l3-K5N2mp?L{o$ zq*f-!!)vCtVajg zxWip|7k{(O8vKKLL}a0M^95fEpFlF_)(uby(;l1Kxh?n^Q|F64b88viboZvW1o$BVoLgXC#_abEZlB9! zav>KW9;!)FgM8qBPDYjaC0L-QRV**0XvP!n3SsIy1h?9Uy1IwOeJBbO#tgtXlQ2$K z!QKWjtRCQ+HR2CoP)W`jac=P~AgRZD#x9?|(V&0J;H4`-_-%NJrx#Gk*(F|sk(*a$ zwk7ycc_|#&`JOg}LCob1bD>7eeJYU0)T)?U)fbry8Yb%3d@kV@CctgYo;7f-@Ocqz zBzH;b8g^f+sr2KaFD9uhJssM_Q^NcUaQC~>sf^BQmf%LH8^(VIjeLo{ODt>v1?WE@=KdFW zE64D#0rJ@`tSwKn;3RG^E8RoiD4{`v?%TJ~Rs8_ERa3YNupP4EhQ zw*P&QD(xkd5Frc}|0m~(KHf_Xp z(+iMI)T;*Ll4noJx^E+qdJ_)v9I^1AU{+0v*4VB!=%^fy(a$AEPo*C*buw*0W+RU9RbKXk5vRzvCyp^}Ihh*JsWL?@Ih4Hz4 zWgQ!HcizrjuvI5_M=gj#7?a$p&Mw<|`-*dxyW}MQ)&OxdeUZc(ykP26C`XFvQ`ux8 z2ytzEprvF5GT?bb!Ot+h`*G$|p!d(E@-s-%#vs!&xzTG}ZoL>xj*FEm!}u`L@rA6N zMCKoYcfcKFv`ZiFco@cGDQ@OG>~|D0uP`4!|C92eR=S5S%GwylXm*A7Sh!RVVxiWt zxe-)pOO>_2ROlyG{k%=bQg7jq&Tu-e5*jkN!lo$;r_6g+?WgrH82;-A?W^%b==^g2TlS?l2d@JGz`!ehX<;&_+RzCZmA8Dv zzFD5|J?JfXys};OHi+l&X1E4}$h7DnSFqx$4?5A}?y!z8(Hps*^ATkIXJEnC#v$1p zY^gJr;f2hCm--cWEdm^8TG>mn6~tMITM$i>^Rd+O&!Cpkf_!$r0qgsEu!v3fv9voh zye4RV2njS82<{L<8{o%B_@XhIAh$~S$gX4-8X9FNppQld-u+YZ?ha~F(nqzWz{y7~ zGD3rb?Khm#vdAv{r0Z{z6{#OX zy;vi>t4zOLHsFHE?9@A;p?aw1#A&7zU7Aj(R3lf3gi{Z&py2)^tZmSU@cdk+LTy5$ z&cl9&y_Af-3$+1!e4Hy8;nxRQ>Yzh^fry906;`RAz<}5AW=M6$yJnZ~aMu6}G-!-<3o`L_K(_PGpSBz;BKRnVfkwH*&0tlsII>vf82wqOZan;ib0x^k#K;3~A z)f-S0W(?{153%WEL8rxtqmZNOeJpT)>Ze#BXKCLHXQ7k_vwGEn0=)t`7MEL==eg_N zw!7u7yI${}Yk4N=9QIoTZSl?+KctiDLt4^@^uaAM`tT#yTJC_hhO6DSjlz9Yp8g}S LtI~Z~e2@PJ1<9yP literal 0 HcmV?d00001 diff --git a/econ/business.py b/econ/business.py index 9006b93..79999e9 100644 --- a/econ/business.py +++ b/econ/business.py @@ -1,5 +1,5 @@ class Business(): - def __init__(self,production,balance) -> None: + def __init__(self,id,production,balance) -> None: """production (dict): { name: 'Gem', amount: 4, @@ -10,6 +10,7 @@ class Business(): } balance (int): Starting Balance """ + self.id=id self.production=production self.balance=balance #Setup Inventory diff --git a/econ/exchange.py b/econ/exchange.py new file mode 100644 index 0000000..f5bedd5 --- /dev/null +++ b/econ/exchange.py @@ -0,0 +1,172 @@ +_bal="balance" +from lightmatchingengine.lightmatchingengine import LightMatchingEngine,Side,Trade,Order +class Exchange(): + """ + Basic Commodity exchange. + """ + + def __init__(self) -> None: + + self.account={} + self.escrow={} + self.lme=LightMatchingEngine() + self.order_account_map={} + self.orders={} + self.executed_trades=[] + self.order_total_price={} + self.market_rate={} + self.best_ask={} + self.best_bid={} + pass + + def add_to_account(self,account_id,resource,amount): + """ + Adds resources to account escrow + """ + #check if account exists + if account_id not in self.account: + self.account[account_id]={_bal: 0} + #check if ressource exists + if resource not in self.account[account_id]: + self.account[account_id][resource]=0 + + self.account[account_id][resource]+=amount + + def remove_from_account(self,account_id,resource,amount) -> int: + """ + Remove resources from account. Returns amount retrieved + """ + #check if account exists + if account_id not in self.account: + self.account[account_id]={_bal: 0} + #check if ressource exists + if resource not in self.account[account_id]: + self.account[account_id][resource]=0 + ret=amount + remain=self.account[account_id][resource]-amount + if remain<0: + ret=self.account[account_id][resource] + self.account[account_id][resource]=0 + else: + self.account[account_id][resource]-=amount + return ret + + def _move_to_escrow(self,account_id,resource,amount): + """ + Adds resources from account to escrow. Return true if done. + """ + if not self.check_account_resource(account_id,resource,amount): + return False + + #check if account exists + if account_id not in self.escrow: + self.escrow[account_id]={_bal: 0} + #check if ressource exists + if resource not in self.escrow[account_id]: + self.escrow[account_id][resource]=0 + + self.escrow[account_id][resource]+=amount + self.account[account_id][resource]-=amount + return True + + def _move_to_account(self,account_id,resource,amount): + """ + Move resources from escrow to account. + """ + ret=amount + self.escrow[account_id][resource]-=amount + + + if resource not in self.account[account_id]: + self.account[account_id][resource]=0 + self.account[account_id][resource]+=amount + + + def check_account_resource(self,account_id,resource,amount): + """ + Checks if account has sufficient resources in inventory + """ + if account_id not in self.account: + self.account[account_id]={_bal: 0} + #check if ressource exists + if resource not in self.account[account_id]: + self.account[account_id][resource]=0 + + if self.account[account_id][resource]>=amount: + return True + return False + + def submit_order(self,account_id,resource,amount,price,side :int) -> Order: + """ + Submits an order to the exchange if resources are sufficent. + Price is price per single item. + Returns an order if the order is active. Returns None if submit has failed. + """ + # calculate price for complete order fullfilment + full_price=price*amount + + + # Move resources into escrow + if side==Side.BUY: + escrow=self._move_to_escrow(account_id,_bal,full_price) + else: + escrow=self._move_to_escrow(account_id,resource,amount) + + if not escrow: + # no sufficient resources + return None + # create order and execude any trades + order,trades=self.lme.add_order(resource,price,amount,side) + self.orders[order.order_id]=order + self.order_account_map[order.order_id]=account_id + self._execute_trades(trades) + return order + + def _execute_trades(self, trades): + for i in trades: + self._execute_trade(i) + + def _is_order_complete(self,order: Order): + return order.leaves_qty==0 + + def _execute_trade(self, trade: Trade): + account_id=self.order_account_map[trade.order_id] + + # calculate price for trade fullfilment + full_price=trade.trade_price*trade.trade_qty + exprected_price=self.orders[trade.order_id].price*trade.trade_qty + price_diff=exprected_price-full_price + # add to order total + if trade.order_id not in self.order_total_price: + self.order_total_price[trade.order_id]=0 + + self.order_total_price[trade.order_id]+=full_price + + # init escrow if needet + if trade.instmt not in self.escrow[account_id]: + self.escrow[account_id][trade.instmt]=0 + + # first edit escrow + if trade.trade_side==Side.BUY: + self.escrow[account_id][trade.instmt]+=trade.trade_qty + self.escrow[account_id][_bal]-=full_price + # move new resources to account + self._move_to_account(account_id,trade.instmt,trade.trade_qty) + # if deal was better then expected move money back + self._move_to_account(account_id,_bal,price_diff) + else: + self.escrow[account_id][trade.instmt]-=trade.trade_qty + self.escrow[account_id][_bal]+=full_price + # move new bal into account + self._move_to_account(account_id,_bal,full_price) + + + + + + self.executed_trades.append(trade) + #update market rate + self.market_rate[trade.instmt]=trade.trade_price + + + \ No newline at end of file diff --git a/main.py b/main.py index e69de29..cecb423 100644 --- a/main.py +++ b/main.py @@ -0,0 +1,13 @@ +from lightmatchingengine.lightmatchingengine import LightMatchingEngine,Side,Trade,Order +from econ.exchange import Exchange + +cx=Exchange() +cx.add_to_account(0,"balance",1500) +cx.add_to_account(1,"food",50) +cx.add_to_account(2,"food",50) + +order_1=cx.submit_order(1,"food",50,2,side=Side.SELL) +order_2=cx.submit_order(2,"food",50,1,side=Side.SELL) +order_3=cx.submit_order(0,"food",100,2,Side.BUY) + +print("help") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2e03335 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +lightmatchingengine \ No newline at end of file