@@ -61,6 +61,8 @@ class market_history_plugin_impl
61
61
market_history_plugin& _self;
62
62
flat_set<uint32_t > _tracked_buckets;
63
63
uint32_t _maximum_history_per_bucket_size = 1000 ;
64
+ uint32_t _max_order_his_records_per_market = 1000 ;
65
+ uint32_t _max_order_his_seconds_per_market = 259200 ;
64
66
};
65
67
66
68
@@ -81,13 +83,12 @@ struct operation_process_fill_order
81
83
void operator ()( const fill_order_operation& o )const
82
84
{
83
85
// ilog( "processing ${o}", ("o",o) );
84
- const auto & buckets = _plugin.tracked_buckets ();
85
86
auto & db = _plugin.database ();
86
87
const auto & bucket_idx = db.get_index_type <bucket_index>();
87
88
const auto & history_idx = db.get_index_type <history_index>().indices ().get <by_key>();
89
+ const auto & his_time_idx = db.get_index_type <history_index>().indices ().get <by_market_time>();
88
90
89
- auto time = db.head_block_time ();
90
-
91
+ // To save new filled order data
91
92
history_key hkey;
92
93
hkey.base = o.pays .asset_id ;
93
94
hkey.quote = o.receives .asset_id ;
@@ -104,39 +105,54 @@ struct operation_process_fill_order
104
105
105
106
db.create <order_history_object>( [&]( order_history_object& ho ) {
106
107
ho.key = hkey;
107
- ho.time = time ;
108
+ ho.time = _now ;
108
109
ho.op = o;
109
110
});
110
111
111
- /*
112
- hkey.sequence += 200;
112
+ // To remove old filled order data
113
+ const auto max_records = _plugin.max_order_his_records_per_market ();
114
+ hkey.sequence += max_records;
113
115
itr = history_idx.lower_bound ( hkey );
114
- while ( itr != history_idx.end() )
116
+ if ( itr != history_idx.end () && itr-> key . base == hkey. base && itr-> key . quote == hkey. quote )
115
117
{
116
- if( itr->key.base == hkey.base && itr->key.quote == hkey.quote )
118
+ const auto max_seconds = _plugin.max_order_his_seconds_per_market ();
119
+ fc::time_point_sec min_time;
120
+ if ( min_time + max_seconds < _now )
121
+ min_time = _now - max_seconds;
122
+ auto time_itr = his_time_idx.lower_bound ( std::make_tuple ( hkey.base , hkey.quote , min_time ) );
123
+ if ( time_itr != his_time_idx.end () && time_itr->key .base == hkey.base && time_itr->key .quote == hkey.quote )
117
124
{
118
- db.remove( *itr );
119
- itr = history_idx.lower_bound( hkey );
125
+ if ( itr->key .sequence >= time_itr->key .sequence )
126
+ {
127
+ while ( itr != history_idx.end () && itr->key .base == hkey.base && itr->key .quote == hkey.quote )
128
+ {
129
+ auto old_itr = itr;
130
+ ++itr;
131
+ db.remove ( *old_itr );
132
+ }
133
+ }
134
+ else
135
+ {
136
+ while ( time_itr != his_time_idx.end () && time_itr->key .base == hkey.base && time_itr->key .quote == hkey.quote )
137
+ {
138
+ auto old_itr = time_itr;
139
+ ++time_itr;
140
+ db.remove ( *old_itr );
141
+ }
142
+ }
120
143
}
121
- else break;
122
144
}
123
- */
124
145
125
- /* Note: below is not true, because global settlement creates only one fill_order_op.
126
- * for every matched order there are two fill order operations created, one for
127
- * each side. We can filter the duplicates by only considering the fill operations where
128
- * the base > quote
129
- */
130
- /*
131
- if( o.pays.asset_id > o.receives.asset_id )
132
- {
133
- //ilog( " skipping because base > quote" );
134
- return;
135
- }
136
- */
146
+ // To update buckets data, only update for maker orders
137
147
if ( !o.is_maker )
138
148
return ;
139
149
150
+ const auto max_history = _plugin.max_history ();
151
+ if ( max_history == 0 ) return ;
152
+
153
+ const auto & buckets = _plugin.tracked_buckets ();
154
+ if ( buckets.size () == 0 ) return ;
155
+
140
156
bucket_key key;
141
157
key.base = o.pays .asset_id ;
142
158
key.quote = o.receives .asset_id ;
@@ -153,20 +169,19 @@ struct operation_process_fill_order
153
169
if ( fill_price.base .asset_id > fill_price.quote .asset_id )
154
170
fill_price = ~fill_price;
155
171
156
- auto max_history = _plugin.max_history ();
157
172
for ( auto bucket : buckets )
158
173
{
159
174
auto bucket_num = _now.sec_since_epoch () / bucket;
160
- auto cutoff = fc::time_point_sec () ;
175
+ fc::time_point_sec cutoff ;
161
176
if ( bucket_num > max_history )
162
- cutoff = cutoff + fc::seconds ( bucket * ( bucket_num - max_history ) );
177
+ cutoff = cutoff + ( bucket * ( bucket_num - max_history ) );
163
178
164
179
key.seconds = bucket;
165
- key.open = fc::time_point_sec () + fc::seconds ( bucket_num * bucket );
180
+ key.open = fc::time_point_sec () + ( bucket_num * bucket );
166
181
167
182
const auto & by_key_idx = bucket_idx.indices ().get <by_key>();
168
- auto itr = by_key_idx.find ( key );
169
- if ( itr == by_key_idx.end () )
183
+ auto bucket_itr = by_key_idx.find ( key );
184
+ if ( bucket_itr == by_key_idx.end () )
170
185
{ // create new bucket
171
186
/* const auto& obj = */
172
187
db.create <bucket_object>( [&]( bucket_object& b ){
@@ -186,8 +201,8 @@ struct operation_process_fill_order
186
201
}
187
202
else
188
203
{ // update existing bucket
189
- // wlog( " before updating bucket ${b}", ("b",*itr ) );
190
- db.modify ( *itr , [&]( bucket_object& b ){
204
+ // wlog( " before updating bucket ${b}", ("b",*bucket_itr ) );
205
+ db.modify ( *bucket_itr , [&]( bucket_object& b ){
191
206
try {
192
207
b.base_volume += trade_price.base .amount ;
193
208
} catch ( fc::overflow_exception ) {
@@ -211,24 +226,23 @@ struct operation_process_fill_order
211
226
b.low_quote = b.close_quote ;
212
227
}
213
228
});
214
- // wlog( " after bucket bucket ${b}", ("b",*itr ) );
229
+ // wlog( " after bucket bucket ${b}", ("b",*bucket_itr ) );
215
230
}
216
231
217
- if ( max_history != 0 )
218
232
{
219
233
key.open = fc::time_point_sec ();
220
- auto itr = by_key_idx.lower_bound ( key );
234
+ bucket_itr = by_key_idx.lower_bound ( key );
221
235
222
- while ( itr != by_key_idx.end () &&
223
- itr ->key .base == key.base &&
224
- itr ->key .quote == key.quote &&
225
- itr ->key .seconds == bucket &&
226
- itr ->key .open < cutoff )
236
+ while ( bucket_itr != by_key_idx.end () &&
237
+ bucket_itr ->key .base == key.base &&
238
+ bucket_itr ->key .quote == key.quote &&
239
+ bucket_itr ->key .seconds == bucket &&
240
+ bucket_itr ->key .open < cutoff )
227
241
{
228
- // elog( " removing old bucket ${b}", ("b", *itr ) );
229
- auto old_itr = itr ;
230
- ++itr ;
231
- db.remove ( *old_itr );
242
+ // elog( " removing old bucket ${b}", ("b", *bucket_itr ) );
243
+ auto old_bucket_itr = bucket_itr ;
244
+ ++bucket_itr ;
245
+ db.remove ( *old_bucket_itr );
232
246
}
233
247
}
234
248
}
@@ -240,9 +254,6 @@ market_history_plugin_impl::~market_history_plugin_impl()
240
254
241
255
void market_history_plugin_impl::update_market_histories ( const signed_block& b )
242
256
{
243
- if ( _maximum_history_per_bucket_size == 0 ) return ;
244
- if ( _tracked_buckets.size () == 0 ) return ;
245
-
246
257
graphene::chain::database& db = database ();
247
258
const vector<optional< operation_history_object > >& hist = db.get_applied_operations ();
248
259
for ( const optional< operation_history_object >& o_op : hist )
@@ -286,8 +297,12 @@ void market_history_plugin::plugin_set_program_options(
286
297
cli.add_options ()
287
298
(" bucket-size" , boost::program_options::value<string>()->default_value (" [60,300,900,1800,3600,14400,86400]" ),
288
299
" Track market history by grouping orders into buckets of equal size measured in seconds specified as a JSON array of numbers" )
289
- (" history-per-size" , boost::program_options::value<uint32_t >()->default_value (1000 ),
300
+ (" history-per-size" , boost::program_options::value<uint32_t >()->default_value (1000 ),
290
301
" How far back in time to track history for each bucket size, measured in the number of buckets (default: 1000)" )
302
+ (" max-order-his-records-per-market" , boost::program_options::value<uint32_t >()->default_value (1000 ),
303
+ " Will only store this amount of matched orders for each market in order history for querying, or those meet the other option, which has more data (default: 1000)" )
304
+ (" max-order-his-seconds-per-market" , boost::program_options::value<uint32_t >()->default_value (259200 ),
305
+ " Will only store matched orders in last X seconds for each market in order history for querying, or those meet the other option, which has more data (default: 259200 (3 days))" )
291
306
;
292
307
cfg.add (cli);
293
308
}
@@ -306,6 +321,10 @@ void market_history_plugin::plugin_initialize(const boost::program_options::vari
306
321
}
307
322
if ( options.count ( " history-per-size" ) )
308
323
my->_maximum_history_per_bucket_size = options[" history-per-size" ].as <uint32_t >();
324
+ if ( options.count ( " max-order-his-records-per-market" ) )
325
+ my->_max_order_his_records_per_market = options[" max-order-his-records-per-market" ].as <uint32_t >();
326
+ if ( options.count ( " max-order-his-seconds-per-market" ) )
327
+ my->_max_order_his_seconds_per_market = options[" max-order-his-seconds-per-market" ].as <uint32_t >();
309
328
} FC_CAPTURE_AND_RETHROW () }
310
329
311
330
void market_history_plugin::plugin_startup ()
@@ -322,4 +341,14 @@ uint32_t market_history_plugin::max_history()const
322
341
return my->_maximum_history_per_bucket_size ;
323
342
}
324
343
344
+ uint32_t market_history_plugin::max_order_his_records_per_market ()const
345
+ {
346
+ return my->_max_order_his_records_per_market ;
347
+ }
348
+
349
+ uint32_t market_history_plugin::max_order_his_seconds_per_market ()const
350
+ {
351
+ return my->_max_order_his_seconds_per_market ;
352
+ }
353
+
325
354
} }
0 commit comments