|
Ban Curtain
Member
Offline
Activity: 63
Merit: 10
|
|
April 27, 2013, 12:46:14 PM |
|
Id like to create hierarchy of strategies. The first strategy observes for a complex event and then emits signal which should be handled by slot of the second strategy. How is it better to implement?
As far as I understand to connect to a signal of a dummy emitter I must have access to instance of emitter, but while initializing strategies I have only instance of gox. Is it possible to get access to another strategies' instances?
|
|
|
|
prof7bit (OP)
|
|
April 27, 2013, 01:03:50 PM Last edit: April 27, 2013, 01:29:45 PM by prof7bit |
|
Is it possible to get access to another strategies' instances?
Not in the current implementation, not when passing a list of strategies to the command line. But what you could do is to explicitly load a strategy from within another strategy. This "master strategy" could then load "slave strategies" in an exactly defined order and pass them references to itself or to each other in their constructors so they can refer to each other and then you could have your strategies communicate with custom signals or directly calling each other. Edit: Another ( maybe even better) solution would be that you pass the strategies to the command line in the right order so that the first strategy would be the one that wants to emit signals would simply create a new signal in the gox instance and all the other strategies that load after it would check if a member of that name exists in the gox instance and if it exists connect a slot to it. Emitting Strategy:In the constructor __init__ of the emitting strategy (that one should be loaded first) do the following to create the new the "signal_foo": gox.signal_foo = goxapi.Signal()
and to emit the signal you do something like this: self.gox.signal_foo(self, (42, 23))
Receiving Strategy:in the constructor __init__ of the receiving strategies (these must appear *after* the above one on the command line) you add the following to detect the existence of the signal and connect a slot to it to it: if hasattr(gox, 'signal_foo'): gox.signal_foo.connect(self.slot_foo)
and a slot: def slot_foo(self, sender, data): """slot for custom foo signal""" (a, b) = data self.debug("foo signal detected: %g %g" % (a, b))
That should do the trick, I just tested it and it works very well. If the emitter was not loaded then the slot will just never be called but it won't crash (you can add an else to the if to print a debug warning if that happens)
|
|
|
|
Ban Curtain
Member
Offline
Activity: 63
Merit: 10
|
|
April 27, 2013, 01:52:18 PM |
|
Is it possible to get access to another strategies' instances?
Not in the current implementation, not when passing a list of strategies to the command line. But what you could do is to explicitly load a strategy from within another strategy. This "master strategy" could then load "slave strategies" in an exactly defined order and pass them references to itself or to each other in their constructors so they can refer to each other and then you could have your strategies communicate with custom signals or directly calling each other. Edit: Another ( maybe even better) solution would be that you pass the strategies to the command line in the right order so that the first strategy would be the one that wants to emit signals would simply create a new signal in the gox instance and all the other strategies that load after it would check if a member of that name exists in the gox instance and if it exists connect a slot to it. Emitting Strategy:In the constructor __init__ of the emitting strategy (that one should be loaded first) do the following to create the new the "signal_foo": gox.signal_foo = goxapi.Signal()
and to emit the signal you do something like this: self.gox.signal_foo(self, (42, 23))
Receiving Strategy:in the constructor __init__ of the receiving strategies (these must appear *after* the above one on the command line) you add the following to detect the existence of the signal and connect a slot to it to it: if hasattr(gox, 'signal_foo'): gox.signal_foo.connect(self.slot_foo)
and a slot: def slot_foo(self, sender, data): """slot for custom foo signal""" (a, b) = data self.debug("foo signal detected: %g %g" % (a, b))
That should do the trick, I just tested it and it works very well. If the emitter was not loaded then the slot will just never be called but it won't crash (you can add an else to the if to print a debug warning if that happens) Thank you, I gonna try the solution you recommend.
|
|
|
|
prof7bit (OP)
|
|
April 29, 2013, 03:09:44 PM |
|
goxtool.py can now display a depth chart. Also it has grouping in the orderbook and optionally adding up the totals: git pullthere are a lot of new keyboad shortcuts to control all this, I have added them to the manual: http://prof7bit.github.io/goxtool/Screenshot:
|
|
|
|
ErebusBat
|
|
April 29, 2013, 03:26:35 PM |
|
Thanks prof7bit! Question: what do the yellow Os indicate?
|
|
|
|
prof7bit (OP)
|
|
April 29, 2013, 03:29:07 PM |
|
Thanks prof7bit! Question: what do the yellow Os indicate? They are your own orders. If you zoom out the orderbook (- key) you will see them there too
|
|
|
|
ErebusBat
|
|
April 29, 2013, 03:32:59 PM |
|
They are your own orders. If you zoom out the orderbook (- key) you will see them there too
Oh, awesome! Thanks!
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 29, 2013, 06:59:32 PM Last edit: April 29, 2013, 11:13:53 PM by MtQuid |
|
I'm not very interested by you "speaker" strategy ... for now... but maybe one day it could be useful... I tried to play with a Python wrapper for TA-Lib http://ta-lib.org/http://mrjbq7.github.io/ta-lib/this wrapper is total... you just need to install cython, TA-Lib, and this wrapper I just tried this out and wanted to plot the results so I dumped the data to some files and used Highstock.js to render the view. import goxapi from goxapi import OHLCV import datetime import numpy as np import talib import json
class OHLCV_Encoder(json.JSONEncoder): """JSONEncoder for class OHLCV()""" def default(self, obj): if isinstance(obj, OHLCV): return [obj.tim, obj.opn, obj.hig, obj.low, obj.cls, obj.vol] else: return json.JSONEncoder.default(self, obj)
class Strategy(goxapi.BaseObject): ........ ........
def slot_keypress(self, gox, (key)): if key == ord("t"): """testing talib""" candles = []
for c in reversed(self.gox.history.candles): candles.append( OHLCV( # fix time for HighStock.js JSON import c.tim * 1000, # adjust values to be human readable goxapi.int2float(c.opn, self.gox.currency), goxapi.int2float(c.hig, self.gox.currency), goxapi.int2float(c.low, self.gox.currency), goxapi.int2float(c.cls, self.gox.currency), goxapi.int2float(c.vol, "BTC") ) )
self.debug("Test history with %d candles" % len(candles))
rng = range(len(candles)) iterable = (candles[i].cls for i in rng) a_cls = np.fromiter(iterable, np.float) iterable = (candles[i].tim for i in rng) a_tim = np.fromiter(iterable, np.int64)
a_sma = talib.SMA(a_cls, 10) a_wma = talib.WMA(a_cls, 25)
# create json compatible with HighStock.js with open("talib_ohlcv.json", 'w') as outfile: json.dump(candles, outfile, cls = OHLCV_Encoder) with open("talib_sma.json", 'w') as outfile: # first 10 elements contain Nan json.dump(np.dstack((a_tim[10:], a_sma[10:])).tolist()[0], outfile) with open("talib_wma.json", 'w') as outfile: # first 25 elements contain Nan json.dump(np.dstack((a_tim[25:], a_wma[25:])).tolist()[0], outfile)
with <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>BTC Highstock - Goxtool/TA-Lib</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script type="text/javascript" src="http://code.highcharts.com/stock/highstock.js"></script> <script type="text/javascript" src="http://code.highcharts.com/modules/exporting.js"></script> <script type="text/javascript"> $(function () { var seriesOptions = [], ohlc = [], volume = [] yAxisOptions = [], seriesCounter = 0, names = ['OHLCV', 'SMA', 'WMA'], colors = Highcharts.getOptions().colors, groupingUnits = [ ['week', [1]], ['month', [1, 2, 3, 4, 6]] ];
$.each(names, function (i, name) { $.getJSON('/talib_' + name.toLowerCase() + '.json', function (data) { console.log("Loading " + name); if (name == 'OHLCV') { // split the data set into ohlc and volume var dataLength = data.length; for (i = 0; i < dataLength; i++) { ohlc.push([ data[i][0], // the date data[i][1], // open data[i][2], // high data[i][3], // low data[i][4] // close ]);
volume.push([ data[i][0], // the date data[i][5] // the volume ]) } } else { seriesOptions[i] = { name: name, data: data }; }
// As we're loading the data asynchronously, we don't know what order it will arrive. So // we keep a counter and create the chart when all the data is loaded. seriesCounter++;
if (seriesCounter == names.length) { createChart(); } }); });
// create the chart when all data is loaded
function createChart() { console.log("Creating chart");
$('#container').highcharts('StockChart', { credits: { enabled: false }, chart: { renderTo: container, backgroundColor: { linearGradient: [0, 0, 0, 500], stops: [ [0, 'rgb(255, 255, 255)'], [1, 'rgb(215, 229, 240)'] ] } }, rangeSelector: { buttons: [{ type: 'day', count: 1, text: '1d' }, { type: 'week', count: 1, text: '1w' }, { type: 'month', count: 1, text: '1m' } ], selected: 0, inputEnabled: false },
title: { text: 'BTC Historical - Goxtool/TA-Lib' },
yAxis: [{ title: { text: 'OHLC' }, type: 'logarithmic', height: 200, lineWidth: 2 }, { title: { text: 'Volume' }, type: 'linear', top: 300, height: 100, offset: 0, lineWidth: 2 } ],
plotOptions: { candlestick: { color: '#DD2F29', upColor: '#87DA3B', lineColor: '#666' } },
tooltip: { pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b><br/>', valueDecimals: 2 },
series: [{ type: 'candlestick', name: 'BTC', data: ohlc, dataGrouping: { units: groupingUnits } }, { type: 'column', name: 'Volume', data: volume, yAxis: 1, dataGrouping: { units: groupingUnits } }, seriesOptions[1], seriesOptions[2] ] });
}
}); </script> </head> <body> <div id="container" style="height: 500px; min-width: 600px"></div> </body> </html>
Serve index.html up with python -m SimpleHTTPServer 8080 EDIT: Using close instead of open for EMAs and added python server example
|
|
|
|
ErebusBat
|
|
April 29, 2013, 07:09:20 PM |
|
@MtQuid
How far back does that 'historical' day pull from? Since GoxTool started?
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 29, 2013, 07:30:14 PM |
|
@MtQuid
How far back does that 'historical' day pull from? Since GoxTool started?
It's using the same history candles that prof7bit uses for the trade graph. So it goes back a day in 15 minute blocks. Though you can change the history_timeframe value in goxtool.ini to change the block size.
|
|
|
|
c0inbuster
|
|
April 30, 2013, 05:38:06 AM |
|
I had some problems to see HTML file so I contacted MtQuid using PM I post here for other members in fact you have to run a webserver (and not directly open HTML file with a browser) python -m SimpleHTTPServer 8080 Open index.htm in your web browser using this url http://127.0.0.1:8080/index.hmlYou will get a beautiful chart It will be nice to also make orderbook depth chart with a JS lib Maybe adding this feature to goxgui (goxtool GUI) will be fine https://bitcointalk.org/index.php?topic=176489.80Thnaks MtQuid for your code
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 30, 2013, 08:58:48 AM Last edit: April 30, 2013, 09:12:18 AM by MtQuid |
|
Yep they do look good. I robbed some of the colour styling straight from MtGox.com I only wanted the graph output to make sure the ta-lib functions were returning the correct values so I could use them to control my bot. I don't think this functionality needs to be part of the main goxtool branch but a good strategy plugin using ta-lib would be handy. Like providing values and firing signals that can be caught. And because the data sets are small (1 days worth of trade) you could write the whole index.html file to include the data and then there would be no need for the .json files or a web server. Just pops out a stand alone html page every now and again if that's what you require. I've also moved my function so it automatically gets called when new history arrives. def slot_history_changed(self, history, _dummy): """History has changed so recalculate EMAs"""
Now to try and find the best usage for the ta-lib functions and make some coins..
|
|
|
|
hugolp
Legendary
Offline
Activity: 1148
Merit: 1001
Radix-The Decentralized Finance Protocol
|
|
April 30, 2013, 12:23:56 PM |
|
I only wanted the graph output to make sure the ta-lib functions were returning the correct values so I could use them to control my bot. And how are the results?. I manually created a ema function, basically following the formula you see everywhere in the Internet (f.e. http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages) but Im getting results quite different from bitcoincharts.com, specially for the hourly ema's but almost identical for the 1minute ema's. Because of this my guess was: the formula calculates the sma with the first periods and then starts adding the data as a exponential. I assumed this means that over time with enough data it would converge and that is why the 1minute ema's were almost identical while the hourly ema's were not, since Im getting data of two days and there is only 48 hours while there is 48 * 60 minutes. Does ta-lib get better results with data from one day only? I don't think this functionality needs to be part of the main goxtool branch but a good strategy plugin using ta-lib would be handy. Like providing values and firing signals that can be caught. I actually would love to have the the web part in goxtool, maybe just as a plugin or something. EDIT: Also, can anyone give me a hint on how to create a separate debug file for my bot? The regular debug goxtool file gets too big and its very cumbersome to check.
|
|
|
|
ErebusBat
|
|
April 30, 2013, 12:32:50 PM |
|
MtQuid... Would you be willing to share a basic demo of the Ta-lib integration? I do not live in python so it would be very helpful for me, and I am sure others.
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 30, 2013, 02:06:09 PM |
|
MtQuid... Would you be willing to share a basic demo of the Ta-lib integration? I do not live in python so it would be very helpful for me, and I am sure others.
Ok. We will use TA-Lib for bython from these lovely chaps http://mrjbq7.github.io/ta-lib/index.htmlAssuming you are working on a debian system you will need to do the following to install ta-lib for python If on windows or mac then check http://mrjbq7.github.io/ta-lib/install.htmlsudo apt-get install python-dev sudo easy_install cython
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz tar -xvf ta-lib-0.4.0-src.tar.gz cd ta-lib ./configure --prefix=/usr make
#can use make install here if you want sudo checkinstall
sudo easy_install TA-Lib
Once you have TA-Lib installed this is your strategy """ _talib.py
This example strategy will produce some HighStock.js compatible JSON files """
import numpy as np import talib import datetime import json import strategy import goxapi from goxapi import OHLCV
class OHLCV_Encoder(json.JSONEncoder): """JSONEncoder for class OHLCV()""" def default(self, obj): if isinstance(obj, OHLCV): return [obj.tim, obj.opn, obj.hig, obj.low, obj.cls, obj.vol] else: return json.JSONEncoder.default(self, obj)
class Strategy(strategy.Strategy): """a protfolio rebalancing bot""" def __init__(self, gox): strategy.Strategy.__init__(self, gox)
def slot_history_changed(self, history, _dummy): """History has changed so recalculate EMAs""" candles = []
# read them all - don't wory about the history parameter for c in reversed(self.gox.history.candles): candles.append( OHLCV( # fix time for HighStock.js JSON import c.tim * 1000, # adjust values to be human readable goxapi.int2float(c.opn, self.gox.currency), goxapi.int2float(c.hig, self.gox.currency), goxapi.int2float(c.low, self.gox.currency), goxapi.int2float(c.cls, self.gox.currency), goxapi.int2float(c.vol, "BTC") ) )
self.debug("New EMAs from history with %d candles" % len(candles))
rng = range(len(candles)) iterable = (candles[i].opn for i in rng) a_opn = np.fromiter(iterable, np.float)
iterable = (candles[i].hig for i in rng) a_hig = np.fromiter(iterable, np.float) iterable = (candles[i].low for i in rng) a_low = np.fromiter(iterable, np.float) iterable = (candles[i].cls for i in rng) a_cls = np.fromiter(iterable, np.float)
iterable = (candles[i].vol for i in rng) a_vol = np.fromiter(iterable, np.float)
iterable = (candles[i].tim for i in rng) a_tim = np.fromiter(iterable, np.int64)
a_sma = talib.SMA(a_cls, 10) a_wma = talib.WMA(a_cls, 25) a_chaikin = talib.AD(a_hig, a_low, a_cls, a_vol) a_cdlCounterAttack = talib.CDLCOUNTERATTACK(a_opn, a_hig, a_low, a_cls)
# create json compatible with HighStock.js with open("talib_ohlcv.json", 'w') as outfile: json.dump(candles, outfile, cls = OHLCV_Encoder) with open("talib_sma.json", 'w') as outfile: # first 10 elements contain Nan json.dump(np.dstack((a_tim[10:], a_sma[10:])).tolist()[0], outfile) with open("talib_wma.json", 'w') as outfile: # first 25 elements contain Nan json.dump(np.dstack((a_tim[25:], a_wma[25:])).tolist()[0], outfile) with open("talib_chaikin.json", 'w') as outfile: json.dump(np.dstack((a_tim, a_chaikin)).tolist()[0], outfile) with open("talib_cdlCounterAttack.json", 'w') as outfile: json.dump(np.dstack((a_tim, a_cdlCounterAttack)).tolist()[0], outfile)
# Current price in relation to EMA self.debug("SMA = %f" % a_sma[-1]) self.debug("WMA = %f" % a_wma[-1]) self.debug("CLS = %f" % a_cls[-1])
Run goxtool like so python ./goxtool.py --protocol=websocket --strategy=_talib.py
Create index.html like this <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>BTC Highstock - Goxtool/TA-Lib</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script type="text/javascript" src="http://code.highcharts.com/stock/highstock.js"></script> <script type="text/javascript" src="http://code.highcharts.com/modules/exporting.js"></script> <script type="text/javascript"> $(function () { var seriesOptions = [], ohlc = [], volume = [] yAxisOptions = [], seriesCounter = 0, names = ['OHLCV', 'SMA', 'WMA', 'chaikin'], colors = Highcharts.getOptions().colors, groupingUnits = [ ['week', [1]], ['month', [1, 2, 3, 4, 6]] ];
$.each(names, function (i, name) { $.getJSON('/talib_' + name.toLowerCase() + '.json', function (data) { console.log("Loading " + name); if (name == 'OHLCV') { // split the data set into ohlc and volume var dataLength = data.length; for (i = 0; i < dataLength; i++) { ohlc.push([ data[i][0], // the date data[i][1], // open data[i][2], // high data[i][3], // low data[i][4] // close ]);
volume.push([ data[i][0], // the date data[i][5] // the volume ]) } } else if (name == 'chaikin') { seriesOptions[i] = {
yAxis: 2, name: name, data: data };
} else { seriesOptions[i] = { name: name, data: data }; }
// As we're loading the data asynchronously, we don't know what order it will arrive. So // we keep a counter and create the chart when all the data is loaded. seriesCounter++;
if (seriesCounter == names.length) { createChart(); } }); });
// create the chart when all data is loaded
function createChart() { console.log("Creating chart");
$('#container').highcharts('StockChart', { credits: { enabled: false }, chart: { renderTo: container, backgroundColor: { linearGradient: [0, 0, 0, 500], stops: [ [0, 'rgb(255, 255, 255)'], [1, 'rgb(215, 229, 240)'] ] } }, rangeSelector: { buttons: [{ type: 'day', count: 1, text: '1d' }, { type: 'week', count: 1, text: '1w' }, { type: 'month', count: 1, text: '1m' } ], selected: 0, inputEnabled: false },
title: { text: 'BTC Historical - Goxtool/TA-Lib' },
yAxis: [{ title: { text: 'OHLC' }, type: 'logarithmic', height: 200, lineWidth: 2 }, { title: { text: 'Volume' }, type: 'linear', top: 300, height: 100, offset: 0, lineWidth: 2 }, { title: { text: 'Chakin' }, type: 'linear', top: 450, height: 100, offset: 0, lineWidth: 2 } ],
plotOptions: { candlestick: { color: '#DD2F29', upColor: '#87DA3B', lineColor: '#666' } },
tooltip: { pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b><br/>', valueDecimals: 2 },
series: [{ type: 'candlestick', name: 'BTC', data: ohlc, dataGrouping: { units: groupingUnits } }, { type: 'column', name: 'Volume', data: volume, yAxis: 1, dataGrouping: { units: groupingUnits } }, seriesOptions[1], seriesOptions[2], seriesOptions[3] ] });
}
}); </script> </head> <body> <div id="container" style="height: 1000px; min-width: 600px"></div> </body> </html>
And run a simple web server like this python -m SimpleHTTPServer 8080
Then go to http://localhost:8080/index.html and see sunshine You could have the index.html auto reload with simple script or refresh with your mouse EDIT: Also, can anyone give me a hint on how to create a separate debug file for my bot? The regular debug goxtool file gets too big and its very cumbersome to check.
To reduce debug clutter for writing strategies I use a crafty tail. I did have a cut on the end but it lagged tail -f goxtool.log| grep -E 'Strat|Trace|^[^0-9]'
And how are the results?.
I just loaded the chart along with current data from bitcoin charts and they are pretty similar. http://bitcoincharts.com/charts/chart.json?m=mtgoxUSD&r=1&i=15-minI don't know what weighted moving average function they are using but the data is close enough for my use though I probably should check it out on a few more days before I invest the yacht If you use this data you will need to alter the timestamp for HighStock.js add on 000 (three zeros) EDIT: I haven't checked for the 1 hour EMAs but will do some more testing and experimenting later. Using the TA-Lib you can specify the timeperiod and then ignore those first timeperiod output values as the results settle down. I've used the default values from bitcoincharts. Simple at 10 and Weighted at 25.
|
|
|
|
hugolp
Legendary
Offline
Activity: 1148
Merit: 1001
Radix-The Decentralized Finance Protocol
|
|
April 30, 2013, 03:22:17 PM |
|
EDIT: Also, can anyone give me a hint on how to create a separate debug file for my bot? The regular debug goxtool file gets too big and its very cumbersome to check.
To reduce debug clutter for writing strategies I use a crafty tail. I did have a cut on the end but it lagged tail -f goxtool.log| grep -E 'Strat|Trace|^[^0-9]'
Yeah, thats an option, but I still would preffer to have a different file so I can check it from time to time. And how are the results?.
I just loaded the chart along with current data from bitcoin charts and they are pretty similar. http://bitcoincharts.com/charts/chart.json?m=mtgoxUSD&r=1&i=15-minI don't know what weighted moving average function they are using but the data is close enough for my use though I probably should check it out on a few more days before I invest the yacht If you use this data you will need to alter the timestamp for HighStock.js add on 000 (three zeros) EDIT: I haven't checked for the 1 hour EMAs but will do some more testing and experimenting later. Using the TA-Lib you can specify the timeperiod and then ignore those first timeperiod output values as the results settle down. I've used the default values from bitcoincharts. Simple at 10 and Weighted at 25. Thanks for the direction, I will try using ta-lib between today and tomorrow, hopefully it gives better results that my manually created one (which its not difficult...).
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 30, 2013, 05:24:31 PM Last edit: April 30, 2013, 06:44:12 PM by MtQuid |
|
EDIT: Also, can anyone give me a hint on how to create a separate debug file for my bot? The regular debug goxtool file gets too big and its very cumbersome to check.
To reduce debug clutter for writing strategies I use a crafty tail. I did have a cut on the end but it lagged tail -f goxtool.log| grep -E 'Strat|Trace|^[^0-9]'
Yeah, thats an option, but I still would preffer to have a different file so I can check it from time to time. And how are the results?.
I just loaded the chart along with current data from bitcoin charts and they are pretty similar. http://bitcoincharts.com/charts/chart.json?m=mtgoxUSD&r=1&i=15-minI don't know what weighted moving average function they are using but the data is close enough for my use though I probably should check it out on a few more days before I invest the yacht If you use this data you will need to alter the timestamp for HighStock.js add on 000 (three zeros) EDIT: I haven't checked for the 1 hour EMAs but will do some more testing and experimenting later. Using the TA-Lib you can specify the timeperiod and then ignore those first timeperiod output values as the results settle down. I've used the default values from bitcoincharts. Simple at 10 and Weighted at 25. Thanks for the direction, I will try using ta-lib between today and tomorrow, hopefully it gives better results that my manually created one (which its not difficult...). I just put this together. This will create a log file for each loaded strategy as well as sending log messages to the main log. Maybe prof7bit could check it over and put it into the main source. It's a quick hack but it works. And you call self.debug() just like before and there is a new function self.info() for different log level. Change Strategy.py to look like this. """ trading robot breadboard """
import goxapi import logging
class Strategy(goxapi.BaseObject): # pylint: disable=C0111,W0613,R0201
def __init__(self, gox): goxapi.BaseObject.__init__(self) self.signal_debug.connect(gox.signal_debug) gox.signal_keypress.connect(self.slot_keypress) gox.signal_strategy_unload.connect(self.slot_before_unload) gox.signal_ticker.connect(self.slot_tick) gox.signal_depth.connect(self.slot_depth) gox.signal_trade.connect(self.slot_trade) gox.signal_userorder.connect(self.slot_userorder) gox.orderbook.signal_owns_changed.connect(self.slot_owns_changed) gox.history.signal_changed.connect(self.slot_history_changed) gox.signal_wallet.connect(self.slot_wallet_changed) self.gox = gox self.name = "%s.%s" % \ (self.__class__.__module__, self.__class__.__name__)
self.logger = logging.getLogger(self.name) self.fh = logging.FileHandler(self.name + '.log') formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s') self.fh.setFormatter(formatter) self.fh.setLevel(logging.DEBUG) self.logger.addHandler(self.fh)
self.info("%s loaded" % self.name)
def info(self, *args): """write info event to log. use our logger then send to the base logger""" msg = " ".join([str(x) for x in args]) self.logger.info(msg) goxapi.BaseObject.debug(self, *args)
def debug(self, *args): """write debug event to log. use our logger then send to the base logger""" msg = " ".join([str(x) for x in args]) self.logger.debug(msg) goxapi.BaseObject.debug(self, *args)
def __del__(self): """the strategy object will be garbage collected now, this mainly only exists to produce the log message, so you can make sure it really garbage collects and won't stay in memory on reload. If you don't see this log mesage on reload then you have circular references""" self.debug("%s unloaded" % self.name) self.logger.removeHandler(self.fh)
def slot_before_unload(self, _sender, _data): """the strategy is about to be unloaded. Use this signal to persist any state and also use it to forcefully destroy any circular references to allow it to be properly garbage collected (you might need to do this if you instantiated linked lists or similar structures, the symptom would be that you don't see the 'unloaded' message above.""" pass
def slot_keypress(self, gox, (key)): """a key in has been pressed (only a..z without "q" and "l")""" self.debug("someone pressed the %s key" % chr(key))
def slot_tick(self, gox, (bid, ask)): """a tick message has been received from the streaming API""" pass
def slot_depth(self, gox, (typ, price, volume, total_volume)): """a depth message has been received. Use this only if you want to keep track of the depth and orderbook updates yourself or if you for example want to log all depth messages to a database. This signal comes directly from the streaming API and the gox.orderbook might not yet be updated at this time.""" pass
def slot_trade(self, gox, (date, price, volume, typ, own)): """a trade message has been received. Note that this signal comes directly from the streaming API, it might come before orderbook.owns list has been updated, don't rely on the own orders and wallet already having been updated when this is fired.""" pass
def slot_userorder(self, gox, (price, volume, typ, oid, status)): """this comes directly from the API and owns list might not yet be updated, if you need the new owns list then use slot_owns_changed""" pass
def slot_owns_changed(self, orderbook, _dummy): """this comes *after* userorder and orderbook.owns is updated already. Also note that this signal is sent by the orderbook object, not by gox, so the sender argument is orderbook and not gox. This signal might be useful if you want to detect whether an order has been filled, you count open orders, count pending orders and compare with last count""" pass
def slot_wallet_changed(self, gox, _dummy): """this comes after the wallet has been updated. You can access the new balance like so: gox.wallet["BTC"] or gox.wallet[gox.currency]""" pass
def slot_history_changed(self, history, _dummy): """this is fired whenever a new trade is inserted into the history, you can also use this to query the close price of the most recent candle which is effectvely the price of the last trade message. Contrary to the slot_trade this also fires when streaming API reconnects and re-downloads the trade history, you can use this to implement a stoploss or you could also use it for example to detect when a new candle is opened""" pass
EDIT1: Changed formatter to formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(message)s') EDIT2: Changed call to base debug to use *arg instead of arg so is now goxapi.BaseObject.debug(self, *args) No more edits. Code is flawless EDIT3: Need to remove file handler on strategy unload so that it is not reloaded twice or more during a strategy reload I think that should do it now. Code is never flawless Price is also going down.... Time for tea
|
|
|
|
hugolp
Legendary
Offline
Activity: 1148
Merit: 1001
Radix-The Decentralized Finance Protocol
|
|
April 30, 2013, 08:17:34 PM Last edit: April 30, 2013, 08:27:55 PM by hugolp |
|
MtQuid that looks terrific. Hopefully prof7bit can include that or something similar in the source.
Another solution might be being able to select what goes into the debug at runtime, so one could select to only have in the debug file the messages from the modules s/he wants. Im fine with any of both solutions.
EDIT: MtQuid tried your code and its working perfectly. Im sending you a small tip.
|
|
|
|
MtQuid
Newbie
Offline
Activity: 24
Merit: 0
|
|
April 30, 2013, 11:57:01 PM |
|
EDIT: MtQuid tried your code and its working perfectly. Im sending you a small tip.
Tip recieved. Thanks hugolp
|
|
|
|
|