-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathstockexchange.nls
221 lines (179 loc) · 7.88 KB
/
stockexchange.nls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
globals [
price_limit_top
price_limit_bottom
dd
]
to init-dividends
set dividends []
if data-source = "webAPI"
[
set data first web:make-request "http://api.finance.ifeng.com/akdaily" "GET" (list (list "code" code) (list "type" "last"))
set dd remove "[" remove "]" remove "}" remove "{\"record\":[" data
set dd csv:from-row dd
; "2013-12-30" 2108.883 2112.009 2097.529 2095.063 740850.56 -3.722 -0.18 "2,097.529" "2,097.529" "2,097.529" "740,850.56" "740,850.56" "740,850.56"
while [not empty? dd and is-string? first dd and item 4 first dd = "-"] [
let trade_time time:create first dd
let open_price item 1 dd
let close_price item 3 dd
let volume item 4 dd
set dd sublist dd (ifelse-value (is-string? item 14 dd)[14][15]) (length dd) ; index or stock
if length dd < 14 [stop]
set dividends lput (close_price / ifelse-value (is-string? item 14 dd)[10000][1000]) dividends
]
]
if data-source = "from-file"
[
let sg-data (csv:from-file file-choose ";")
foreach but-first sg-data [ set dividends lput ((first ?)/ 10000) dividends ]
]
if data-source = "monte-carlo"
[ repeat 3800 [ set dividends lput (random-normal 0.02 0.004) dividends ] ]
end
to-report dividend [n]
report item n dividends
end
Stocks-own
[
id
price
price_unit ; minimum price unit
price_precision ;
fundamental ; internal value
hist-price ; historical price
d-table ; a data table used by stats extention
dealed-volume ; #-of dealed shares for each tick
p_lin5 ; predict price 5 ticks afterward based on linear regression
p_lin30 ; stats:forecast-compound-growth-at stats-table variable T
sd ; standard deviation
long-orders
short-orders
total-shares
]
to setup-stocks [stock-num]
set price_limit_top 10000
set price_limit_bottom 1
init-dividends
create-stocks stock-num [
set shape "square"
set size 2
set price_unit 1
set price_precision 0
set price (dividend 0 / r )
set hist-price lput price []
set dealed-volume 0
set d-table stats:newtable
stats:set-names d-table ["price" "intr-value" "dealed-volume" "l-buy" "l-sell" "p_lin5" "p_lin30" "sd" ]
stats:add d-table (list price (dividend 0 / r ) 0 0 0 price price 0 )
stats:use-most-recent d-table 100 ; only calculate recent 100-ticks data
set total-shares 1000 ;
set long-orders []
set short-orders []
set incoming-queue []
;set hidden? true
]
; ask turtles [ set label-color blue ]
end
;; Collecting orders
;; content like [ "buy" "sender:6" "content:" [13 1] "receiver:10" ]
;; [ type-of-bidding sender -investor [price number-of-shares] receiver - stock ID ]
to collect-bids-and-make-deal
set dealed-volume 0
let msg 0
let performative 0
while [not empty? incoming-queue]
[
set msg get-message
set performative get-performative msg
execute-order performative msg ;execute-long-order "bl" msg
]
end
;;; records biddings of type in format: ["bl" "sender:9" "content:" [12 1] "receiver:10"]
to execute-order [order-type msg]
let content get-content msg ;; [12 1]
let bidding-price first content ;; 12
let bidding-volume abs last content ;; 1
let s get-sender msg ;; (who number) 10
if order-type = "bl" or order-type = "bm"
[
if order-type = "bm" [ set bidding-price precision (price + price_unit * 5 ) price_precision ]
;; if bidding-price is higher than current market price, trying to maka a deal with existing counterpart biddings
while [bidding-price > price and price < price_limit_top and bidding-volume > 0 ] ;;
[
let dealing-volume 0
ifelse exist-short-orders-of-price price
[
let bid item 1 get-short-bidding price ;; read a counterpart bidding at price-i like [ 3 12 ]
ifelse bidding-volume < first bid ;; if the current bidding could be "swallowed" by this counterpart
[
set dealing-volume bidding-volume
;; after this dealing, remaining short bidding should added back
add-short-bidding (list bidding-price (list (bidding-volume - first bid) (last bid) ) )
set bidding-volume 0
]
[
set dealing-volume first bid
;; update long bidding order after this dealing
set bidding-volume bidding-volume - dealing-volume
]
;; send message to buyer
send add-receiver s add-content (list price dealing-volume) create-message "buy-order-executed"
;; send message to seller
send add-receiver last bid add-content (list price dealing-volume) create-message "sell-order-executed"
set dealed-volume dealed-volume + abs dealing-volume
]
[ if price < price_limit_top [ set price precision (price + price_unit) price_precision ] ] ;; iterator price
]
;; counterpart at bidding-price is not exist, then add this order to long-bidding list
if order-type = "bl" and bidding-volume > 0 [
add-long-bidding (list bidding-price (list bidding-volume s))
if show_messages? [show (word "add-long-bidding "bidding-volume" shares at price "bidding-price )]
;; [ 1 [ 2 5 ] ]
]
]
if order-type = "sl" or order-type = "sm"
[
if order-type = "sm" [ set bidding-price precision (price - price_unit * 5 ) price_precision ]
;; if bidding-price is lower than current market price, trying to maka a deal with existing counterpart biddings
while [bidding-price < price and price > price_limit_bottom and bidding-volume > 0.1 and bidding-price > 0.5] ;;
[
let dealing-volume 0
ifelse exist-long-orders-of-price price
[
let bid item 1 get-long-bidding price ;; read a counterpart bidding at price-i like [ 3 12 ]
ifelse bidding-volume < first bid ;; if the bidding could be "swallowed" by this counterpart
[
set dealing-volume bidding-volume
;; after this dealing, remaining short bidding should added back
add-long-bidding (list bidding-price (list (bidding-volume - first bid) (last bid) ) )
set bidding-volume 0
]
[ set dealing-volume round first bid
;; update long bidding order after this dealing
set bidding-volume bidding-volume - dealing-volume
]
;; send message to buyer
send add-receiver s add-content (list price dealing-volume) create-message "buy-order-executed"
;; send message to seller
send add-receiver last bid add-content (list price dealing-volume) create-message "sell-order-executed"
set dealed-volume dealed-volume + abs dealing-volume
]
[ if price > price_limit_bottom [ set price precision (price - price_unit ) price_precision ] ] ;; iterator price
]
;; counterpart at bidding-price is not exist, then add this order to short-bidding list
if order-type = "sl" and bidding-volume > 0 and bidding-price > 0 [
add-short-bidding (list bidding-price (list bidding-volume s))
if show_messages? [ show (word "add-short-bidding "bidding-volume" shares at price "bidding-price ) ]
;; [ 1 [ 2 5 ] ]
]
]
end
to update-stock-tables
if ticks > 100 [ stats:trim-data d-table 100 ]
; move according to price
;set ycor round price / 10
set hist-price lput price hist-price
set p_lin5 stats:forecast-linear-growth-at d-table "price" 5
set p_lin30 stats:forecast-compound-growth-at d-table "price" 30
; ["price" "intr-value" "dealed-volume" "l-buy" "l-sell" "p_lin5" "p_lin30" "sd" ]
stats:add d-table (list price (dividend ticks / r * 100) dealed-volume length long-orders length short-orders p_lin5 p_lin30 sd )
end