Initial checkin

--HG--
branch : sandbox
This commit is contained in:
Andreas
2009-06-24 19:11:31 +00:00
parent e554144922
commit 773d4dfe6c
17 changed files with 2313 additions and 0 deletions

17
.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sandbox</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

12
.pydevproject Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/sandbox/src</path>
<path>/sandbox/gui</path>
<path>/sandbox/mpl</path>
</pydev_pathproperty>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
</pydev_project>

View File

@@ -0,0 +1,3 @@
#Mon Feb 11 22:12:56 CET 2008
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false

View File

@@ -0,0 +1,4 @@
#Mon Feb 11 22:12:56 CET 2008
eclipse.preferences.version=1
project.repository.kind=trac
project.repository.url=http\://localhost\:8080/xmlrpc

View File

@@ -0,0 +1,6 @@
#Mon Feb 11 22:12:56 CET 2008
DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;
USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;
USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;
USER_PREFERENCE=overrideGlobalPreferencesfalse
eclipse.preferences.version=1

365
gui/bottier.py Normal file
View File

@@ -0,0 +1,365 @@
# Copyright (c) 2008 Andreas Balogh
# See LICENSE for details.
""" decode ASCII greyscale """
# system imports
import Tkinter as Tk
import logging
from StringIO import StringIO
from PIL import Image
from PIL import ImageTk
# local imports
# constants
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
CODE = "#MWmBEKNQkAbqXHgUFRhdwp8&aDGVZ9utO03CYvlrI=i<7+?}(*[/|;!^-~`,:. "
def main():
tkis = []
# build gui
root = Tk.Tk()
root.title("bottier")
bu1 = Tk.Button(root, text='Quit', command= root.quit)
bu1.pack(side = Tk.BOTTOM, padx = 5, pady = 5)
for s in (PIC1, PIC2, PIC3, PIC4, PIC5):
im = ascii2img(s)
tki = ImageTk.PhotoImage(im, gamma = 2)
tkis.append(tki)
la = Tk.Label(root, image = tki)
la.pack(side = Tk.RIGHT, padx = 5, pady = 5)
root.mainloop()
root.destroy()
def ascii2img(s):
# create the image
# lines = StringIO(s).readlines()
# height = len(lines)
# width = len(lines[0])
# im = Image.new("L", (width, height))
im = Image.new("L", (100, 100))
for y, line in enumerate(StringIO(s)):
for x, c in enumerate(line):
im.putpixel((x, y), CODE.find(c) * 4)
bbox = im.getbbox()
bbim = im.crop(bbox)
imx2 = bbim.resize((bbox[2]*2, bbox[3]*2), Image.ANTIALIAS)
return imx2
PIC1 = """\
BEmmmBBBBBNNEBBEEKBBHd&aDGapHNBEBBBBEKBEmBBEBBKgdp8wdRbEBKEEEEENKQNAAbbXUp8aD9
BEBBBEKENNNEBEEKEEmAd8DZVG&RkEBmBBEEKBBBmmmmBBmbh&Da&wFQBmmmBmBmmmBWmmmBmmmBmm
mBBBBBEKNKKKKKKENBkh8VVZGDwXNEBBBEEBBBBBmWmmmmmEgwaDGDpFKBBmmmmmmWmWWmWWWWWmmW
EEBBKBEKNNKNEEEQEER&VZ99V8gNKBEBBEBEBBBmmmmmmmmWqh&DVGawqmEmBmmmmmBWmWWmWWMWWM
KEBKEEKNKKKKKNNNBqG9OOtuGhAKEEEEBBBBBBBBBmmBBBmmEgwaDaa8RNBBBmBBBmmmmWWmWMWWWM
BBBBENKQNKENNQNNmRu0003taXNKKEKEBEEBEBmmBBBmmBBmmNF8aDDawXKmWBBWBmmmMWWmWWWMMM
EKEBKNkQNKNNNNQNBRO333YO&bQNKKKKBBBmWMWWMWWmmmBmmWAR8VGG&hbBmWWmmmWWWWMMMMMMMM
NKEENAAkNKNkQNkKQ&3YYvvO&AKEEEBBmWWMMMMW#MMMMMMMMMWEgpGGDawbBBmBmBWmmWWWMWMWMM
NKEKkAkkKNKkQQkKXZClrIv3DbNEWMMMMM#MMM#MM#MMM#MMMMMMmNgZZGVwEmBmmmWmmmmmWWWMM#
QNQkkQQkNQQkkAkERtYr=Il3VHKWMMMMMMMMMM#M#MMWMMMMMMMMMEAdZVZREEmBBmmWmmmmmWWWMW
kbkbAkQkNQQAkkQEpOv=i=rY9hBWWMWMMMMMMWMMBABmWMMWWWWMWWN899VdKEEBBmmmWmBBmmmWWW
AbbbbkkkNQbbAQQNDCrii=Iv9dKmMMMMMMMMWWWmBXAKEmKghFQmMMBqVt9&QEEBBmBmmBBmmmmmmm
bqqXXAkQNAqqXbQAG3I<<iIvOpEWMMMMWMMWWmEAAwdHXdpwdhRNWmBKp3tDqEEBKmEBmBmmmmBmBm
qHgHHAbkkAXgHHAXZli7<i=l38EWWWMMMWmBAhhpwRdhRUgUgHHNmBQUCYOGUKEEBKBBBBBBBmmBBB
XggUUXbkAqgUUUkguli7<<ir3DKmMWWWWBkggHggqXXbXXqHgbbbbAXGYGO9dQEEEEBmEBBmmBBmBm
FhhRdFqqAqRRUFkFOr=<7<irCaNWmMWWmQqHbXggHFUddHgggHRgHFdOGaCt&ANNEmEBEmBBBBBmmB
UUFddhgbqgRFFUAR0ri<++iICDkmmmmmKAbURRgFa8DpRdRwRRdqbqUUdYv0GbKKEEEKKBEBBBBBmm
RFFdwpFXXUhdFUkhOIi77+<ICGQmmBKkUHHwgpR&hw8h&ahUqbqbg8Rd0lv3ZXKKKKKKKNKEEBEBBB
hhdhwwRgUhhdhFbh3=<++7<il9kBWmEbXgRRGDut0tuDVDwaagbHARw0IIr3ugQNNNKEENNKEBEBBm
8phhppwwdwwwhhqwYi7?+++7i0HEmBKbHhhZOO3v3u0O9VpDuaXUaOlIIIrCuUkNNQNKKKKEEBmEEB
aDDa&8pwpppppdXdvi7++???<YaXAQKEKKgGtO3Y33Y0tZGDuDhdZCI=IIlCuUkNQNNNKEEBBBEEEE
GVZVVVa&8w&&&8gwv<++?}}(+ICaHEEKEBNHwD900Cvvl0VaGwHwuv==I=IvtFkQkNQQNEEKKEEEBE
ZZt99OuVVGGGGaRdvi?}???}}<iC8NBKEBBba&aDDVVGa&wFbEA&Ori===rvtUkkQNNNNEKEKEEEEE
ttO0030uuu9ZZGahY<+?++?}}?+I0hKEmBENFVOrl3t&wRNBEKFD0IiiiIrvtgAkQNNNNNKEEEEEEE
3033YYY3C333OuVF3<}}+++}?}}7rOHBEEKkHaCiiI0DwkBmBBbVv=i===rvtgAkQQQQKNENKKKEKK
YYYvvrvvvlvrrrthZ<(?7+?+}?}?+lDQKBEQhaY==ru&XEBBBKptlrIlrIrYZHAkkQkQNNNNNKKNNN
Ylll===llr=I=Il9a=}(((((**[}?=OUkBBNUVli=twAKBBENUuvlrlvvrrCZXAkAkkkkQQQQNNKNN
I=II<7+=r=i=i=It&=([////*[}?}7IZUAkHUUlrY9dqXQKAdpZlrrvvYlrYaqAAAAbQkQQNQQQNKK
<77+}}}+7i7+77I0G7*/|;|||*?????ItG&wdGCCttDpRUh8030YI<rCCvl0RqqbbAbkkkkkkQNNNN
+??((((?+??+???OO}/;!;!;|}<+?}?7rCvvvlCC3COOO0ClI=Ili+irYvYVHqbbAbbQQkQQQQNNQQ
?(*[[/[*}}*(*(+Vr*/;!^^!*7<<?}?7<rvlrIrr=IllvvrIi=il=?<=rl3hXXHqbbbAAAAAkQkkQQ
([/;///|*[*(*}=V<*/;;;|(i=i7?}}}?+<<<<7+<7iI=i===iIYv7+iIltUHXXXqqbbAAAkkQQQQN
/;!^^!;^;!||[*r9?[|//*?II<7+?((???777+}(*(??++<<i=rvYI77rvZUHgHXXqXAAAkAkkkNNQ
;|^~-------^!!79+*/[(<==<<??}*[[**}??+***}}?++<<i=rY0trirvGgHHXXHXqAbbkAkkkkNQ
!-~~~`~~~```~~*t<(}}<rI=7?++}*|;|/[(+?*/[[(*}?+77i=C09uYlY&gXqXXXXqqbAkkkQNQNQ
~`,`~,,`::.:,:^tI+?<rvY7+7=lr<|^!;;[?+*|[*[***}?+7i<ltVZ30hHXXXXXbbbAkkkkkQkQN
,::::::..,:.::~CC<+<lr7}?rY3O9=!^!|[*(/||[//|[*(}?77r99Vu9RXXXXHXXbAAkkAQQNQNN
:.......:,`:.:,=0i77rr+?OZ&&aGO(^;|[([|;|////|/[*}+i0ui++=38Z&hgHHqbbbkAkQQQQN
....::..`,`,::`lOi+?7I=+3DD&Z8ZY///[[|!;!!;||||[[(+Y0=7++=p03Cu3Y0DUbAkkQNNQNk
....::,.:. `.:,<tr+}(+=rC8a&GY+////|;!!!!!;|/|||[*}IY33CYa0YviI0u33gkkQQkQNNNN
:.............:[Or<}}(}+=a37}(*[/|;!^!!;!;;/[[*(}+irrt8UgdD9ZutO00RAAkNkQNKKKK
,:::.:.:::.:,``v9l<?((*[*((*[/[/|!;|;!!;|//*(+7<=rYODapFgUHbQqhG9FbAQQkKNNNNKK
,`,`:::``,,~`-!Otl<?(*[///[/||||;!;||!||[((}?7ilY0t9uDRgggHHqqqqqbkkNkQQNNKKNN
!``~,,,----`~~-Z9ri+([[/[[[//||;;!;;;!|!//*(}?7=IlvC9hHgHgXbqqqbbAkQNNNKKKKKKK
/!!!!^^!|!;;!;*aVl<}*[[[**/|;;;!;;;|!;!//[(?++<iiIl0aFgggUHHbqqbAANkQNNNKEKEEK
}([;;|/;[/|/[[+pZv<?}(([(*[|;!!;||!|;;;!||[*+7<iirC9RFggUHHHXbbbkkNNQQKNEEEKKE
7?}**/*//|/[**?aGvi+?(*(**|;!;;!;/||;||;;/[*}+<IlY3GUgHHUHHqbbAkkkQkNNKKNKENEE
77++??}***((}(7&Dv=7?(**|||||;;;;;!|/|||||/*(?irYCtpgggUgXbHXAAAQkNKNNNNNNKKEE
I=<<i<<+++?+++<p&Oli+(*[[|||||/|;;;||||//**[*?irYOaFHHXHXXqXqAAkkQkQNKNNNEKEBE
rIIIIIi<7<=<77<p&tCI<?}([[[|//////|||//[[((}}+7ICZdXHXXXqbbbAbAkANQQNNQQQKEKEB
3ClrlI<<<r=<<7rh&tvri7?}***/**/[[[[**[(*((?+++iv9pUHXXqqbbbXAAAAkNQNQNNQNNKEKB
0Yrlvi<=i=rrI=ZRG0vI=<+?}?(***[((?}?((}}++77<=vupFqbXqAAkkkkkAkAkQkkQkNKNNKKEm
O0YCCIiIrvYY3VRau3r=i7+??}(***(*}?}}??+77<<=lCOGpUqbbbAbAAQQQkAkkkQQkNNNKNKKKE
tu0CCYrlllCODFaV3vIi<7++?}?}***(?7?}}?}<7iIrY3uVadqAbAAAbAkNQNQQQkQQNQQQNNQKKE
ZtO30YYY33OVU8ZuClI<7???}??((*(}<r=+++++<=rv30t9ZagqbAAAkkkkkQkQNNNKNNNNNKNNKK
DutOttu99u9Uq89O3vr<<777??}}(*(?7i<+7?7<iIlvYC0OuGdbbAbAAAkQNNNKNQKNKNNNNKNKKE
&DVV9GaDGDhBWmBkFVYIiii<77+?}((}}++++?7<=rYY00OOOZwAkQQAAkQNNKNNEEKNNKBKEEEEEE
d&aa8&8&8hNBBEBWBBEKXp90vll=i<i<i<i<i==lvC0OtuZagEMMNNkQkkQNNNNEKEEKEEKBBEKEBE
Rwppw&DDdAMWWWWBbAbXEkEEEEENbqHUhdd8wFFgqQNBBWWmmEBMBKNNQNNNNNKEKEKKEKBEBBBBmB
URwwpw&pqmWmNBBNEKbFQUqbFQUXAgNAkEkgXKBEBEENENKQKKW#MEQNQQNNNNEKEEKEBBBBEmmBBm
gRhdhRhqmQghqHQNBAKANHXkgkgHAhAHHQgQbqQqBkEKBNKQEBmmMMKNQQQNNKEKKEBBEBEBBBBmBm
gFFFRdwFkXaZOtuwgAQBBAAQXBbbKXEAqQXKAQQABQBNEBBNBmWENAkQNNQNNKEEEBBBBBBmBmBBBB
bgRRUhdFNUa9OYvlvpFbQWWmEQQKbXQEkkENbBmNEmEBmBWWkNkgawXNQQNNNKEENKBBEEBBmBmBmm
AAqXggHqKRDu0CvvvlvpKmQNNQkAbbbkAkQkQkNKKKNNNNKWBqGZG8gQKNbkKKKKEEEEEBWmBBBBmm
kkkAbAAKkwGt3YYlvYCdKNgDu9u99ttV99GVZG&D&&GVZ9ZkKGu99&RQNNNNNEEKKKEKEEBmmBBBBB
QKQQQkQEgaVt0CvvY3DKkV9u9uVVVtuu9ZVGDDDaDGZ99ut8Bqtt9DwbQNKKEKKEKKEEEEBBBmBEmm
NNENNQEAhGZOCvYvvtbN&u9VDa&DDVGGapp88p8p8&DZuO0tgK&ttV&gNNKNNKKEKKEKKBEBBBBBBB
NKKQQKKg8Duu0YvY3FNhuZVGD&ppwdhRggUUFUFdp&GuO00OZNNVuVahANKNNKEEEKEEEEBEBEmBBB
KKKKNBbR8GZt0YCCpNUttuZZG&hFHqbbbAAkqXgwaV99ttO0OwBXu9&wqNEKEKEEKKKKNKKEBEBEBB
KEEKEEXRpaVuO33VNqu0tuZVDadHAQKNNNNKNXhpDZZutOO00uABpVGwgNEKEEEEEKEEKEEBBBmmmE
NNEEWMBQFwaGuuaQku0t9ZVa&pRXEBmBWWBBQHRpDGuutOO000aEKaawqBEEEBBBEKKNKEKEEEEBmm
bkEEWWWWWWBQUgNbaOOOuZGDawUbKKNKNEmEbghw&DV9ttt0OO9XEghNWWEEEBBBBEENNKEEEEBBBB
AqkKmBmmmMmmmBmEbdGVGGG&8dgkNNQNNNEmAUhp&DGV99u9VV&HWWmmmWBEKBBEEKEKKEEEEEEBBB
7IYuG8wUHXqAQNKKNNENqRwdhFHNNKKNNNKmKXgRw&&&a8hbEBmmEBBBBmmBBEBEKBEEKEEEEBBBEm
"""
PIC2 = """\
*[}7[/*7+//|[i[/[(i+il0uDahFHXqqbAkkNEKkkNEEBmBBBKQkQAAQKBBEBBBEBENEKEKEEBEBBB
<<++??+?(}}?}??+i====Ii+([/[/|*(}??+7=ii=il3VdgbkkNQkQkkkkNNNNNQNKNNEQEmmEEEEm
<<77+++++?}???+<i=IrlI<7}[/|;/(*}?++7<===rY0GRqAAQkQkkkkkQkQQNKKEEKKEKBBEBEEBB
?+??++??????}?+7<=IrlrIi+([[[[[*}???+iIiIIvOaFXbkkkkNQkkkkkNQQQNKKNNNKKBEEEBmE
}}?}}?}}}((}(?777iIrlvri7}*[/[/**[(?7<ii=rYt&UHbkAkkkkAAAkKkQQNNNKKNNNEKEEEEEB
((((((}(}}??+++7<=rvlvlIi?(*[/*[**(??7==IrYt8gXbkbkkAAkkAAQAQNQQNNQQNNNKEEEEEm
*(((***}}}???7<<i=IIvllrIi+}*[/*[(}+<<i=rv3ZpUXbAAAkkAbAkkQkQQQQkQNKKKNKKEEEBW
[*****}}}???+++<==Irvvvvl=<7}((*((??+iiIrv0VwgqbAAAbAAbAAAkkkkkkQQQNKQNKBBEKKE
*}}**(((}}(+77<<<=IllvCCYlIi+?((??+++i==Il0VwHqbkkkAbAAAkkbkkkAAkkkQKKNKNNKEBB
/[**(}}}}?}++++7iIrrlv333CYli7?}(}++7<iirvOVwHbAAAbAkkkkkAkKQAAAkkkKKKKKKEEEBB
[(****((}??????7iIrlY330OO03ri<?}??+7i==rvtDhXbqbkkAAkkkkNNQQQQQQQQQNQNEEEEEKE
[(**[/[((*((??++<IrvvC3Otuut3lI<77+7<i==rYODhHqbAAAQQQQkkNNQNQkkQQQQKQQKKEBEEB
*[**[[[***((}}}?7=rrYC00Ot99O0Y=<<<<ii=Ir3u&FHXbkQkQQQQQkQkNNQkkkkkQkKKKNKKKKE
||[*[[**[[**}}??+<=llCC0Otuu9t0vlI=ii==rv0ZpUXbAkQNNNNNQkQQQQkkQQQQkKNKNNNNKKE
[|//[**[*(*}}}?++?<IilvY3Ou9ZZO0Cvr===lvY3DdgbAAbNQKKNkkQQQNQQkkQNKQkQkQQNEKKN
^!;||[*[[/[**(}}}++7<iIlCOu99ZVu0ClIIrrrvtaRXbbkQQNkQNNQkQNQkQkkQQQNQNNNKEKKEB
-!^!!||;//[**(??}}??+<irY3O99ZaG9t3YrrlvCt&FqbbkkNQkNNNQkQQNQQkQQkQNNENEEBEEBW
-^!^^!;;///[[*(((***??<Iv3u9ZVGDGu03CYYYOVdgqbkQkNNkNQkQNQNAQQQQNKKENEEKKKEEEB
~--^!;!!|||;|/[**[*(}?7=l0u9VZD&DVuO3YY3tGRXbAQNQQNkQQkQKKQkQQQkQNNQNKKKEEBBmK
`-~-^!!!!;;|/[[[***(*?+=v0tu9VGa&aZt03Y0t&hHbkkQQNNkNQQNNQkkAkAkNNNNNNEBBEBmBB
-~~~~-^^!;!||[[[[[***(+ilOZZuuuZVV9utOOuVpFHbkQNQNQNNQQNQkQAAkQQQkQQQNKEEBEEBE
,,`~~--^!^;!|||//[[*(}+ICuVuCr=rYC330Ou9VwhFHqAAQkkkkkkkQkAAbQQQQQNQNNNKEBEEEK
,```~~-^^;!;;/////[*(+<ltVZOr7}((}+7<irC0ZaphUqqXHHHXbkAbbAQAkQQQkkQQQNEEEKKBB
::`````---~^;|||[*(??<lOZZt3I7?*[////[}+i=Y09awdwaG&whFUgXXbkbAkQQQQkNNKKKEKEE
^:,``~~~~~^^^;||[*(?<r3u9u0v<((*/||//[/*(?7IOD8Dt33C0t9Ga8phFFgXqqbAQNKKKKKKEE
.. :,`-~^^-^;|||[(7rY0ut3v=}(*(/|////[/(}iO8d89YvvYvvYCC3OtZDaphUgHXkQNQQNKBE
[:::,`~~``--^!;|[(7IC003Y=7?(*//|||/[*[*}itphdDYiI303vlvYCvCCYC3t9ZDwFUHXbkNKK
,:.::,`~~`---!;|[}<l0CYvr<?}([[[/////*[}It&hpZCI=IC3Yrl39uO3lIii=IIrC3uVpFHANE
..:::::`~-~-^!;|[*?ilvvvr=<7}(([[*****}70&p89Y=ilCllIiICtu990vI=<7<=<==YOGRAKK
.,::::,`~~~--!;;/[(?iIvYvlrIII7?+}}}(?+Caw8ZC=iIvvI<++<=Iv0tttOYlI===irY3VFQKB
.::,::,`~~----^!;[(7==IrlvvvCvvllrrlrvOD8a9Yi<=vvl=i+}}?+<rCCtttO03vIrv0GRAKEW
`:,:,,```~-^^!!;[(+<++<=lYC303C03OtttuVDVu3Ii=lYvl=r=<7<i==rvCOu9Zu0333ZdqKEBB
:,```~~~^-!^;;|[*}+<+??7=vCOZGDVGGGVVVZttOCvvC3CrlO9u033OOtO0Otu99ut309hbNKEBB
,~------^!;;///*}?7<77+irYOZawwRFgHgFhp&aGZuuuO3COZVVZ999uuttOOOO0330ZdXQEBBBB
^^!^!!!^!|*[[((}?+<<iirlYO9apwwhHANKKNQAAUFhp&GGt9Zu0YvvYvvrrrlrlCC0ZRqNEEEKEE
!;;;||||/[*(?}+77i==rlY3tV8wwpdUHXbkQKNKKKEKQkbgRdp&Vt03YlII====IYOGFANEBBEEEm
;;|/[[[**}(+++7i=rlvY0uVD8wp&wdFHqqXXbAAAAKBmmmmWBQbgRpaG9tC3YvvCOGdXQEBBmBEBm
/**((}?}?++<<Irlv300uZD8p8aa&wUqXqqqbqbqqqbAQNKEmWMWmEKNbgUd&GZZZDhqQKEKKEBBmW
/((???++<<IIrlY30t9Vapp&aaDGwhHbAbbqXqbbXbqbAkAQKKBBWWWMWMmEkHRhFHbQQEBmEKEBBW
}}+7<<ii=rlYY3Otu9VGaDGVVGD8hgXbAAAbXqAqbqbkkAAQQQKBBBmmBBmEKkAbANNNEEEBBmWWWW
((+77<==IvvCCC0OOttZutu9ZG&dRgqbAAAAbqbbqkkkkAkkQQNKEKKKKKKENNQNNKEEBmmBmmmWWB
**}?+<<i=IllvYYYCCC333OuZDpFHqAAAqbAbbbbqAkkAAkQKKKEKNKEKKKNQQQNKEBBBWmmBBWWMW
/*}}?+<ii==rrlvvYYvYv0OuG8hgXbbkAbAAAAbbAkkkkAANKKKNNKKKKKKKKKNNEBBmWWWmmWMM#W
/[*((?777<===IrIIrrlC0tVadFHbbkAbqbAkkbAAkQkQNNKKQNKEKNKKKKKQNEEBmmmWWMWWMWWMM
[***(}?++7<i====I=IvCOuV8RgqbkAkAAkkkAbAQkQNQNNQQQNNEKKEKKKEEEEBmWWmmWmWWBBWEM
[[[***(}}}7<7<<i=IIv3tV&dUqbqAAAbbAkkAbAQQNNNNQQNNKKEEEKNKKKEBBBBBEBBmBmmWMMWN
[[[**(}(}}+?7<i==IrY39awRHbbbbbAbAAAAAAAkQQQkkkQNKNKKKKNKNNEEEBBEEBBWmmmWMWmWW
*[(*(}}(}?}?7<<i=rY3OZahUHXAAbAkAkkAAqbqqAAkkAAQQKKEKKNKKNKKEKEBBEKBWM#WmmmmWW
**(**(((}???<<<iIrv0uVpRgXXqqqqbAAbAAAAqqbAAkkQQNNNQQQNEBEBEEEEEBEEBMWMWWWWmmM
"""
PIC3 = """\
MMM#MM##MWMD{8M##MM####MMMMMM###M##M###MMM########M####MM##MMMMMMMMMMM#MMMWWMM
M#MMMMM#M@A=2WWMWWMMM##M#MMM#W##M######M##M#M##M##MM###MM##MMWMMMMMMW##M#MMMMM
MM##MWMBiW%oWMUmWWW@NM##MMWymM############M#MM###MM#MM##M#MMMMMMMMMMMW#MMMMMMM
WMMWqmWMMW=B#WiWM#B?8WMMWWXmWMM###M#####MMMM###MMMM#M#M##M#MMMMMMMMMWMMMMMWMMW
WWWgDD8@&9%#MBD####WWmmWWLmMW#MWM#####MWM#M#M##MM##M#MM#MMM#M#MMM#MWWMMMMMMWMM
mWWWWmQWWCWWMMM###MWWBWMWWmcvxFXmMMM#MMMMMM#MMMMM#M#MMM##M#MMMMMMMMMMMMMMMWWMM
MMMMMWWW$@#MMMM##M#WMW@WmAWi)77z@MMMMM##MM###M####MM##MM#M##MMMMMMMMMMWWMMMMWW
WWWWWWWMFWMMMMMM#MMMMMWWWWAB313QWMMMMMMMMM#MMM#####MMM#MMM#M#M#MMMMMMMWMMWMMBm
MWmWWWWMmMMMMMMMMM#M#M#kWWWMW<&WMMM##M#MM#M##M#MM#MMMMMWMMM#MMMM#MMMMMWMMMMMWW
WN,NMWWmW#WMWWMMMMMMMWWMM##MMW&@MMMMM#MMM#######MMM#M#M#M#MMMMFWMMMM#MWmMMMMWW
MMMMMMMMWMMMMMMMM#MMYmMMMMmmWMMMMMWMMMMMMM###M#MMMMM#####MMMM#MMMMMMMM<3MMMWWW
##MMMMMWWMMMMMWWWWWMMWMMMMMMWW##Xu3bmmWWWM#M#MMMMMMMMM##MMMM#M#MM#MMMMWMMMMMMM
MMWMM#MMW#MMWMMWWWWWWWMMWWMMM##MME%D=3@mWWMMMMMMMMWWMMMMMMM#M#MMMMM#MMMMMMMMWM
WMMMM#MMmWWmmMMWWWWWWAWMQWMMMMMMMM80/38NWWMMWMMMMMWmBWWM###MMMMMMMM#WMMWWWWMWM
M#MMWMMMMm8WWWWWMMWWWmWWMMMMM#MMWWWm<D<?8mMMMWMWMMM@@@mMWM#M#MMMMMWYY#MMMWMmWW
MMWWMWWWWm@mmmWWWWQWWMWWMWWMMMMMWW]))|'`)lmm@BWWWWmQXNm@QNmWMMM#MWMMMMMWMMMMWW
MWWWMMMWMWmWmmmmmWWWMWM#WMMWMMMMMMW<^))-~'':::'`?ocv2%d$k$QmMMMMMMMMMWMMMMMWWW
WWWMMMW#MMWmmmmWMMWWM#MMNU#MMMMMM#m?))|-':: '-^~-|7=Y9q8qkmWMMMWMMMMWWWMMMWMM
WM#MMMMMMWWWMWWWMWWWWMWWWWMWMMMMMW8||)-' .^~..')|?lzL8UqNmWMMMMMMMMMMMMMMMW
MMMMMMMMWWWWWWWWmmmOO988@@mNWmQbQW=)|"~:. '^:. :-)[iYOy&$kmWWMMMMMMMMMMMMMMM
#MMMWMWWWmmmmBBQmN&qA8eD9QAmWk@Q$<__[|': ._,:::~_/1v02DU$mmWMMMMMMMMMWWMMWM
WMMWWmWMWmWmmAREEby8&=3xqN@mMWMMN<|||-:... .:-)-;;"+<cj0L68bmmWMMMMMMWWBWWMWWW
##MMMMMMWMW@NF&@mmRkejv8BmWMMWWmm@O<?~:::::,-^|)/"]<1vvj26&bmmWMMMMMM#MWMMMM#W
MMMMMMM##MWm@gygNmAQ88&BM#MMMMMWWMMmv':.,~;|7|)||/"<ivY3xt&@mWM##MMM#MWMM#MMM#
M#MM##M##M###MMMMMWM###M#MMMMMM##MMMD`.:~_)+=7||"{+<1vvjtu&@@mMMMM##MMMMMMMMMM
M#M#######M##M####W###M#M##MM##M###MD:.::-_+7l/{[+<1olzY098N@mMMMMM#MMM#MMMM#M
M##M##M##M##M#M#M#W#M#MMMM#MMM###MMM&)~':'^_/7?|?711llv3xL8@QWM#M#M#MMMMMMMMMM
MM#####M##M####M##M##M###MMMM#####MM82+)-)_)/[=+{{<1==YC2L8N@WM#MMMMMMMMMMMMMM
######MM#MM#MMM#MM######M##M#######MMQL3Ii==o=x7<++<<cYjtDX@EmWMM#M###M##MMMMM
M######M#MMMM#MMM##MM############M##M9v+]oL8Dyg=7<<1=lx2eR@NmmWWWMMMMMM##MMM#M
########MM##MMMM##M######MMMMMMM#MWBQci1+{7<<=xl<<1clj96&F@mm@BWWWWMM#MM#MMMMM
MM#WM###MMM####MM######MMWBU&AMWb2=Yj/]Ll<+7<1vtIo=Yx3ey&8@NbFqNmmWWWMM#M##MMM
#M##M#MMM#M##M#M#MMWk%3i<++{{iWW&l+8811%R2YlI=c9CYvlC0t6DdEF88UA@@mmWWWMMM#MMM
#MM#M#MMM###MMWUY<7{[_;)__^_)|gWDvuMmMM#MQDxYYvx6Yvj026yDgN&&88dUg@BmWmWM#MM#M
####M#MMM#MWu1/|;-~-~~,`-~-;^)yWACbBWWM&BW&u6DD8RYvv3u6yFA$66yD&88qX@EmWMMM#MM
#MM#####M#B<);;`,:::,:,,',^-^;?WW9z+?2mMmmQ2e88C==ojO9&8R$&vj0O2%%&R$@EmWMMMMM
#M#M###MMWi|~`,:,,~'~,,,`-`--);lWB=++2mMWEWF9jo1ilO9&gX88U2x00Oxt9D&FX@EmWWMMM
M#MM##MMMm<|)););~~~',~--^___;){B9<7<l@MmWWLcllYx9%&88FbL03jzCj32t6&8gg@BWWMMM
#MM#M####MdYc<7")_^;;_//[++77<i=e1<<=ygNNolYYxuy88gAkk89O2xxz3Yjj3Le%8Xb@mWMMW
#M########MMmbDY<<7icY3xe88U8Fg@l]0ov8WMFYv29D8ddbQ@@R8Dyutt3zYvz3z2Dy8$@mWWMM
#######M####MMWm@$QmWmNQkAUd8dXmxlk<9@@M#m8D&8A@E@N@BA8&9O3Yll1oYYx2eDFQ@mWM#M
#########MMMMMMMMMWWmBNQ@N@mWM##MFd3DuzzoI111<<77+<<<=3%6l<7<<7iIz2%&&dANWM#MM
M##MMM##MM##MMM#MMMM#MMM###M#MMN63lo<7<+?{"{[[+[{{[??+7<<iY<777<IYxLy8q@mW#M#M
######M##MMWMM#MMMMMM##MMMW8xl=<7+[[||||"|///"[/+{??{++71<1oOzcIv3%D8$QBmMW#MM
#M###M##MMWMM##MMMMMMMW@xv=7{"||)-);;)||[/""/+++<]]++<<7111cljjj0O%&XQNmMMM#MM
#####MM##M####M#####Wt=]{|))-^));;||"[+{[?{++<<ic=1=ooIccvvYC92u9y88q@mWMM###M
#MMM#######M#####MAc<[);^---;-_))||/"{?++<71icIllYvvvC332uL9%%D&8UXQNWM#####MM
#M#M########M#MMg<+|)--`-;_))||)/{"[?+7]<iilcYjCCxe2D%e&D%8&8UFXb@mW##M######M
######M#######MY7);':'`__|"{/[[//"{7771illYv0OtDu&6&8RgFXq$kQ@NmM####M####MMM#
#M#M#MM#M#M#MMdl7|;)/"{{{/{]+?{7<<1=olYz03Cuy&&dRFqA$Q@@BBmmW###########M#M###
#M#######MM###mLI=<<1<<<7i71<iilY3CO2y6Y888RbAQmBBmWWMM##########M###M######MM
#MM############m6CYYYCCYYvCj2e&8$qQQ@BNmWmmWWWMM###########M####M##########M#M
######M########MmF&D8XdFARF$QB@RgdgAkNmWmWMM#####M###M###M#MM#M#MM##M##M##M###
###M###########M##MMWmmWmmB@kb@BmWWWM##########M##MM####MM###M####MM#M#####MMM
#MMM#######M######M######M##M#M##M#####M###############M#M#MM#MM#M#M####M#MM#M
MMM#M#M######M##M#MM#M#########MMMMM#M##########MM#M###M#M##MMMM#MMMWMWMMMMWMM
"""
PIC4 = """\
N@NEKEBmmmmmWmmmmmmmmmmWWmmmWWWWmWWmWWmWWWWWWWWWWWWWmBuWWWWWMMWWWWWMMMMWMWMMWM
BEEmmBmmmBmmmmmmmmmmmWmmWmWWWWWWWWmWmWWWWWWWWWWWWWWWWGDWWMWWMMMWMWMWMMWMMMMMMM
BBBBBmmmBmmmmmmmmWWWWWWmmWWmWWWWWWWWWWWWWWWWWWWWWWWWWv$WMWWWWMWWWWWWMWMMMMMMMM
EEKBmmmmmmmmmWmmmmmWWWWWWWWWWmWWWWWWWWWWWWWWWWWWWWWWmoBMWMWWWWMMMMMMMMMMWMMMMM
EKmBmmmmmmmmmmmmWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWUYmWWMWWWMWMMMMWMMMMMMMMMM
NEEBmmmmmmmWmmmmmmWWWWWWWWWWWWWWWWWWWWWmWWWWWWWWWWMWuTWWMMMWMMWMMWMMMMMMMMMMMM
EEBmBmmmmmmmmmmBmmWWWWWWWWWWWWWWWWWWWWE5Ugx8bWWWWWWWxqWWMMMMMMMMMMMMMMMMMMMMMM
KEmBmmmmmWmmmWmmmmmWmWWWWWWWWWWWWmBWWqc=~|&AY<&mWWWWbmMMMMMMMMMMMMMMMMMMMM#MMM
NmEBBmmmmmmmWWmWmWWWWWWWWWWWWWWWmthb24x,_?)--`'xmWMWWMWMMMWMMMMMMMMM#M#MMMMMMM
NEEBBmmmmmmmWmmWmWmWWWWWWWWWWWWmz8$o{_```'...::<mWWWMMWMMMMMMMMMMMMMMMMM#MMMMM
EEEEEmmmmmmWmmWWKmWWWWWWWWWWWWW@~,vv),::. ::<@WWMWWWMMMMMMMMMMMMMMMM#####MMM
BE@EBmmmmmmmWWWWmEWWWWWWmWmWWWWN<'D8v<+)-',|<=hWWWWWWWMMMMMMMM#MMMM#MM#MMM#MMM
EBEEmEmmmWmWWWWWmbWWWWWWWWWWWBmB?7Fl[)|);~,,-?kWWWmWWWMWMMMMMMMMMMMM######MMMM
@NEEBmBmWmmmmmmWW8mWWWWWWmWWWWWV)RL|'-_;`.:<&lbmWWWmWWWMMWWMMMMMMM#MMMMM##MM#M
8@EmmmmmmWmmWWWmm&mWWWWWWWWWWWB):Ut<+17?-:|o@WWWMWWWWWMMMMMMMM#M#MMMM###M##M##
u8NEBmmmmmWWWmmmWmWWWWWWWWWWmm<..nlvaOi{{ovv08mWWWWWMWWMMMMMM#MM########M#M##M
t&KBBmmmmWWWWWWWWmmWWWWWWWBLL<:..88QA2l&$e2t2J==qWWWWWMMMMM#MMMMM##M###M#M####
xD@mmmmmmmWWmWWWWWBWWWWA"1uY1/):-$mEA&BWEU@E@&TYlleKWWWWMMMMMM#MM#M#####M#####
J8EmmmmmmmWWWWWWWWmWWWK^:.'=8&8GuUWWmmQgBWWWME&l7|-;"v@WMMMM#M#M##M###M#M###MM
vSKmmmmWWWWWWWWWWWWWWWX: .|=7AW&A8mWkXAmWMMMM@0+)':'`-<mWMMMMMMM#M###MM######
04bmmmmWWWWmWWWWWWWWWWW8^.<LooT@mWWWWmXG&@WMMMN5</~~'''`vBWWWMMM#M#########M##
uj8BmmWmWWWWWWWWWWWmWMWQ.:Lg=<D58@WWWmFt3vx8NmmQ&j<{);~~?1IlkWWMMMM#M#####MMM#
Sj%NmmWWWWWWWWWWWWWmWWWo :Jge32xG@MMWKhuxv<+[?=TgQA&C<||o<[|lI8mMM##M#######MM
&JxABmWWWWWWWWWWWWWmWMW< .<g@qYI3QWWmQ8S0v=+|~'-^3Em@8xd8t1<<+|7YmMM##M#######
&jJ&mmWWWWWWWWWWWMMWWWWe..=mWmo)<QWWNd%2jv<{_^`~~|UWWmmmEbqxl<?)|"jmMM##M###M#
8OCnNWWmWWWWWWWMWMMMWMWQ.:8MMW2~|QWN8uYzlo+/^~,:~~^LMMMWWmqb8aTl]{"1m#########
8&23$mmWWmWWWMWWWWMMMMWl<YWWMMg,)gW@V3=<??|;-`~`,-|8WMMMMMWWmmbDjo<<&###M#####
8&308mWWWWWWWWWMMMWMMMWD5XWMMMm/_JAmA3<|;~`,~-;~;|?UMMMMMWWMWWmb&nOGW###M#####
URLCSNWWWWWWMMWWMMWMMMMMRlmMMMWe+4NWmgY+");__/|||[{eWMWWWmWWmmNQbkWM#######M##
bdn3TbWWWWWWWMMWWWMMMMMMMWe&WMMRYuKWMWgTzI==1<+{/[<io8WWmWWWWWmWM#############
AF&O48mWWWWWMWWMMMMWMMMMMMW<LBWQ2gWMMMm@X%2Oz=7++71ilio&ENq8YDEM####M#########
QmBB@EmWWWWWMMMMMMMMMMMMM##WD$WWU8W#MmX&nLVe2zc<1lc<77<<lXX00bhllN############
d888e28&@mF&NWWMWMMMMMMMMM###WBNmEWMMWmQFgbR&5303zc<+++<11l&&t4CoB############
8&S0C03Qmm@qXbKWMMMMMMMMMM#M##M#WWWMMMWWWWmm@AbqU%2v<<1<1<<1ogWWMM#M##########
$X&G8bAX88gAbbKBmMMMMMMMWMMMMMM#MMX5mWMMMMMMMMWm@UaLxxCl=<]++<NMM#M#########MM
g8&GaGnVD&nxux&UEWMMMMMMMMWMMMM##MA{i&@28@mmWWWmXt0x020xJYo1iouW#M############
QS0zzYJ0G8%t25&ABmW#MMMMM#MM#M#MMM8""13TEWmWm@Ov3O2Cv===IlvvJvY@M############M
E&23jjY3TV%0tVdkWMMMMMMMMMMWmQd&kmX7i5QWMMMmo<TFdV2l1<<<+71Izlc2WMMM##MM###M#M
mQ8&V2TeeOJO2%XmMMWMWWguzYjtGFmWMMMWQ&WM#MD;)8mEb8tY]{[++]7<1JzlbMMMMMM#MWWMW#
mmm@kAQgDSnVRRBW@L<1vT&8&Su55LeAWMMMMME&b0;:7WWmQU&0+)|/"+{+<oCYRMMMW&1""/7/xl
WWWmWmWWWWWm8l7c0GdhR88R8FXXqANNWMM###M#Mc<JmMMWm@U&0o7<7+<czOn2QW%+"|//||))+4
WWWWWWWWA=-)l8UbgXXqAk@KmmWWWWMM#M####M#Md8qM##MMWmbdn33YvluEmgL["+77+<+<"|<IB
mWWWWmY.:<&AQ@@Q@@EmmWWWWMM#MMM#M######M#MWm@M####MWAq&%%D%C&WEXh3Jxl7<+|1]tL@
WWWWB?'0@NKNEmmWWWWWMMMMMMWMMM#M#M#M######BzX@######MNXbbQqRg8F&&e8G32%5+i]YSm
mN@@X2NmmmmWWWWMWMMMMMMM#MMWWmmWM##M#######mmQm######MWWWWND%g@$ASVFF88b=++C8&
/|+=jFmWWWWWWMWWMMMMMMMMM#MM####M#################M###MmENhRqQR&bEb8exCJvollzj
|)?<?x@mWWWWWMMMMMMMMMM##MM#M###MM###############MW@FdR&&%TeGhQb$Q&2xYvllllvj3
]~'|I3T@mWWWWWWWMMMMMWMMM#M#M#MMM#MMM#M###M######MWK@gg8zv28hqEmbGuYvvlvvvzJ33
@bh8VtO2L&QWWWWWWMMMWMMMM#M#MMMMMM#M##M####M#M#M##MmN@Q$8V&d@WWgCYocllvlvYjj32
mmmmWmWmWmWWWWWWWWMMMMM#MMMMMM#MMMM#MMMM#####M#MM#MmBm@@@@mBAA@A0ll0u4vvvY3045
mmmmmmmEQq@mmNba&@mWmWWWWMMMMMMMMMM#MMM#M##M#MWWWW@NWBmmBKdz@MW&tJvll2EWWB&qSd
"""
PIC5 = """\
VDGZGaGVZVVVGVGZVZGO0O3CYYvvvCYYC3C3YvCvlYCllvrlvvvrvrvIrlrIIIrl=r==I=7~
9V9ZuV9uVZV99ZVZuttt3CCYlrlI=IIIrlllYlYrIrrYrIllvrrrlvlrIrrI==IIrIIIi=7`
9utuOtt9ttu9utttuOt033YvvlvriI==ii<IrlrrrII=I=rrIIvIrllvIrrIr==III=i=<<`
9tuOtOOtt00Ot00O000tC0Ot0vllII===<7iirrl=iii=<iI<Iii==IIII==i==i<<<<7++`
u0O003O3CC33333YCCDFKNkFwFNKEqD3=ii7?++7<++i7?7?<7<7<7i<<=<7<<ii<<+7+77,
9OC3CYCCCYvC3YY3uHmKqbQKBM##BkNKQZr=I=<+++???+++777777<7+7+<<+<<7i7++7}`
t3CCCYCvYvlCYtUkNKQKEKkbBMMMMWBKEkYIl=iIi77777<<+<=<i77+<<<<i=<77<++7+(:
3YClYrllYIlOEW#MWM##MmmNNWWWWMmNEkbY===I=i==i<i=====iii=<<77<<<<i=<+??}:
O0YlvrIrlOhmWBMM###MNkAKBQmWEQQKNKKNC<+<<ii===I=irI=I=I=<==Iii==<7=i<++,
OOvYlrIlDB#mWEKKKM###mmWKFmNKAKKkQKNq7}?+?+77<=iIIIr=I=====I=r=I===<7<+,
03Y0lvIYDWWBMKNNW#####W#MMBQAQAQEKKNKd?}((}}}??+<<<rI==iirI=III=riiii<}:
Ou30vlrr0QM##QdFKM###M##mWmmBKQQQNKKEQr*(*}*(*(}(}+777+iiiiI<i==i=r=ii7:
uuO03v=iIlaXAkdlrRB#WWmAQMmEBEBmmEKBEN3([*[[[[[/[*(?++?7?+7+<<7<77i<77+:
OOt0CYlIl<<iIYbHZCGBMkuC<OWBBMMBMBmmBK3}+((}*//[[[[*[?(((}(??}?}}}}7+?(.
ut9tO0YvI=I=rYHH0YIVEN&ppuXB#W#MWmBN8Y3Y7}?}(([(*[**[**/*[/[[(*((}}***[:
ZZ99ttCCYlrrIuOUGv<+rGaUavHW#MWWWEAqw8NQaul=7?+}?(((*[*****[[*/[*[[**[/:
aGDZV9tt03vvlCY&X&07++}l}+uNEHd8wqEmMWAqXNKU0<7?}+??}(}([[*[**[*/(*/[//
&pa&8GVZut0OYYYOdXF8VCIIY&dw&DpgEBNq&VXKHXdHHgv7i7<7777++?}}(}*}*([[*//.
Fhdw&8a&aZZuuuOuwOXKKKQbqqF&&FKmmWBXDZi?IagqURbhIII=<i<7++???}}}+((}*[/:
UhRhdR&Rp8a&DaVZGDhFwZZI=rZhFqkQKEHabC```~~^[uggROrrI=i<7+<7<7777+?(?(}`
gXUgFUFRFFhww88aDDapah&VDFUkQKWmWE8hGi^`,``~`^;/ZUguri==<<<ii<<++777<7},
qXXqAXHHqXHFRRRwRdRwpp&88&DhBmENKgZaU=^,`,```~~~-;CAFOiiii<ii<7i+++7i7?~
qbbAkQbbAqXqXXXgu3I0&UqAFdwFmEEEBKXUUi^,,,,,,``,``~|pbhlii<<7==i7=}??7+-
kkNkQQNQkQkANbHli(/(}}rGXAFhRmBKAQR8V+!~`,`,,,`~,`--~|dAZ===<<=<<<<<<77~
QQQKQKNENKKKQkar?[;/**(+3hAUFFqEQNkkV</^,``,~`~~~~``-!}gqHI<7iii<<<i<7+;
KNKKKEKEEBmEmqV<}[/*}(*?<vDqHggNKKkkpr/-,`-`~~^--^^^![iDXqhti==iI=iii7<!
EBKNEBEEBmmmWKGvi*(?7?[[?ivakXXNEEKkFt=*!-^!^;|-~^/|[/+lFXgD8r<=I=I<i<i/
BmEBBBNmmmmmEEgtl<7?+l?/*?IORNHAKKNQQhGvI77[[|!--~~^[*?ihgU8GD=<<ii=ii<*
mWEKBBEBmmM#WWkOGtI+[=VI?+<38QKbKKENKmQUp9Ci}(*;;--``!/i9UUFwQa===Ii=i<(
WmWmBBmWmmWWMMNDFZI?[(vwI7<lZqWKQEmBKNEEKbRa3Ii?*[!!--;+CwUggkEtvlr==Ir+
###MWWmWWMmBWMm8gG<}*[7ZViirVUKmbABKNAXgkmmAU8uvi?*[[||([IhUg0YOYl==iir+
WmmBWMMWWWBWMmV?[[}7**+lh3rr0aqHUwgBQNqdpRHkQkXwZ0vii<<~!/Zpw0vllYvlrI=?
WWBBEBmWBmBEVvr7(;-;[<=rh9viIOkFhUpUD0i((+}<OdwpDu=[;|;;|;|l333C3YYlIrI<
EmEBBBNBMBN0=ii+[!^^|/(?Y9Y7<rGEqXNAt=*;-~`~;IaqKAU89CI<?(/[}C03YvC3YllI
KKEEEEBmmBAV=+7+[|!;/[*++=Y+/;!}9m#kI9?*^^^^^;|*ONENAgdVOl7([[lO3O0YCCYv
KQKKEEEBEEkgC7ilI=<?*((}}7iYI[7=8X7}?Og37?}<l<}[;|CkBKAXRa0Y?}*?=0v03YYl
QkkKKENBEEKkA83YCvvr=i+???7iCCrI[7YRWWMmERa3?}**[}(*OXEKNAX8VI<?*}OOOt0l
AkNQKENEBEBBAAqV0vvYvrI=i77<il3tvqdMmKKAXUt<7?([;!^;/[ObBNQQqwZC=+tu9uu0
qqbQKEBmEKKEKFFF&9OCYvr=Iri=rrY0uaR#Kg&pXbpGu3llIi77=v30XNKEXUhGua&V9Z9O
bQXbqkkEBKKEmERQghau0CvlIrI=rrrvCtDHKF8DDF&VZuv3C=<?7?(i0kNBNkgqFRpGu9ut
HQqHbkQKEEBEBWkG8KXwD90Cvvlrllvv0C39OG9tutVVOv=7((/;!|[}IGbFNEKENbHDt003
AXbgqqkQBBBEKmMkw9hBgdaGuCvvvvYCClCtu[lYCY3OCl=+((/;|/[*7vUhRMBBmEb&aVO0
XgbXgqbNEEBEBBBmBH&8MkFR8ZOOOY003C0tO;v7VDGVVtCrI<+(**(}}70=UEMMmQu[(lVG
bqAAbkNQKEBBEW#MmmkUFWmAXhaZutOO3C3Y|[l}=qRFDDV3I7?(([(?i=0Cw0YXbv|YOuVZ
bkQkkkNNEmWMMWMM##MKqX#BNAHh&DVuu0l;+r0**uXMqZ3v=+(*[//}=3&bQ9li/-(aGaGG
XAkkANKEmmMWMM##M##MBEN#WNAqUwa9=/=CO9}<7YGhkM#NDv<777=IYVHWgvv?[rV&GV9t
HbkKQAEEBm###########X0v0ZuOIi=uuV&V(O[ir0tDa93g##WUG3Ot98Q#KwV3rCGV&V9t
UHAkkEKKKBm#####QKBW####WEqp0ll=iYC++Ilv0Y0uu3vI7lQ#WWM###M#MERGYlCZGZZ9
RFHXbQkkNKE#Wkd&GZaXm#######WX8VOO3OtttO0333vl=777+vBBBWM##M#ERZ3vvtFaVt
hhFFUXXbbkKq=rIlrCZpdAKBW#####BkRpDV9tt0CCrII77+<+7iCEM##KBMMmduYZV3G8G9
FFUgFaD&qpI7=i=lYYCtu9u&Q#######mQXp&utOCCi==i<7==rY0FM#QgbWMEdY0wEwtu&D
dU830OZ9Iii=Iv0D899u9OVhW#########mNUd&VtO3CYY330OuG&b#NggdgW#KgZt9Rh003
R8VRZr====IOUWNNEKHkgXXqAQBW########MKkUd8&&&Da&&&8RbWbXgghUHXbKMKpZVUZV
wF0Yv9hXXbqUdppw8wwwhFFgqAkkEKEWM#####WmKkbXUUUgqqkEkqqkqqgXgqXbgRdD&V9V
dppa&8888Fd&D8pdhFhhhFUhbXbbANAkQkkEEBWM##MWWBBEEbXHUgXUgFXHAbbHXURUwp9t
hFd8pdhRwh88dRdddRggqqHFUHHbQQANQNqbAAkbqbkXqXHXUUggRRhFhggqAqUFgUgFhphp
&dhphRhdFw8ddFHUXHXXHqkXbUgRQQKQkbbAXXbAXHHgFRRFRwpdwUXFFHHHHFhRwwwd8GaG
RgRRRFhhFRFUFggFHAqUXgbqXbXgHbAkQkXbbgFUhRw88pp88p8pdppw8&ggwwFw&8&&8D&9
hFwwwdRggRUgUHUbXXqXbggbqHXgUggXUgUURhwww88&&88aVZVZGGDDZ&ZDpD8u9uZ&GGGZ
"""
if __name__ == "__main__":
main()

449
mpl/fibionacci.py Normal file
View File

@@ -0,0 +1,449 @@
# Copyright (c) 2008 Andreas Balogh
# See LICENSE for details.
""" animated drawing of ticks
using self.canvas embedded in Tk application
Fibionacci retracements of 61.8, 50.0, 38.2, 23.6 % of min and max
"""
# system imports
import datetime
import os
import re
import logging
import sys
import warnings
import Tkinter as Tk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num
# local imports
# constants
ONE_MINUTE = 60. / 86400.
LOW, NONE, HIGH = range(-1, 2)
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
MDF_REO = re.compile("(..):(..):(..)\.*(\d+)*")
def tdl(tick_date):
""" returns a list of tick tuples (cdt, last) for specified day """
fiid = "846900"
year = tick_date.strftime("%Y")
yyyymmdd = tick_date.strftime("%Y%m%d")
filename = "%s.csv" % (fiid)
filepath = os.path.join("d:\\rttrd-prd-var\\consors-mdf\\data", year, yyyymmdd, filename)
x = [ ]
y = [ ]
fh = open(filepath, "r")
try:
prev_last = ""
for line in fh:
flds = line.split(",")
# determine file version
if flds[2] == "LAST":
last = float(flds[3])
vol = float(flds[4])
else:
last = float(flds[4])
vol = 0.0
# skip ticks with same last price
if prev_last == last:
continue
else:
prev_last = last
# parse time
mobj = MDF_REO.match(flds[0])
if mobj is None:
raise ValueError("no match for [%s]" % (flds[0],))
(hh, mm, ss, ms) = mobj.groups()
if ms:
c_time = datetime.time(int(hh), int(mm), int(ss), int(ms) * 1000)
else:
c_time = datetime.time(int(hh), int(mm), int(ss))
cdt = datetime.datetime.combine(tick_date, c_time)
x.append(date2num(cdt))
y.append(last)
finally:
fh.close()
# throw away first line of file (close price from previous day)
del x[0]
del y[0]
return (x, y)
class Lohi:
"""Time series online low and high detector."""
def __init__(self, bias):
assert(bias > 0)
self.bias = bias
self.low0 = None
self.high0 = None
self.prev_lohi = NONE
self.lohis = [ ]
self.lows = [ ]
self.highs = [ ]
def __call__(self, tick):
"""Add extended tick to the max min parser.
@param tick: The value of the current tick.
@type tick: tuple(cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
# automatic initialisation
if self.low0 is None:
self.low0 = tick
self.lows.append((n, cdt, last - 1))
if self.high0 is None:
self.high0 = tick
self.highs.append((n, cdt, last + 1))
if last > self.high0[2]:
self.high0 = tick
if self.prev_lohi == NONE:
if self.high0[2] > self.low0[2] + self.bias:
res = self.high0
self.low0 = self.high0
self.lows.append(self.high0)
self.lohis.append(self.high0)
self.prev_lohi = HIGH
if last < self.low0[2]:
self.low0 = tick
if self.prev_lohi == NONE:
if self.low0[2] < self.high0[2] - self.bias:
res = self.low0
self.high0 = self.low0
self.lows.append(self.low0)
self.lohis.append(self.low0)
self.prev_lohi = LOW
if self.high0[1] < cdt - ONE_MINUTE and \
((self.prev_lohi == LOW and \
self.high0[2] > self.lows[-1][2] + self.bias) or
(self.prev_lohi == HIGH and \
self.high0[2] > self.highs[-1][2])):
res = self.high0
self.low0 = self.high0
self.highs.append(self.high0)
self.lohis.append(self.high0)
self.prev_lohi = HIGH
if self.low0[1] < cdt - ONE_MINUTE and \
((self.prev_lohi == LOW and \
self.low0[2] < self.lows[-1][2]) or
(self.prev_lohi == HIGH and \
self.low0[2] < self.highs[-1][2] - self.bias)):
res = self.low0
self.high0 = self.low0
self.lows.append(self.low0)
self.lohis.append(self.low0)
self.prev_lohi = LOW
if res:
return (self.prev_lohi, res)
else:
return None
class Acp:
"""Always correct predictor"""
def __init__(self, lows, highs):
self.lows = lows
self.highs = highs
def __call__(self, tick):
"""Always correct predictor.
Requires previous run of DelayedAcp to determine lows and highs.
@param tick: The value of the current tick.
@type tick: tuple(n, cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
return res
def find_lows_highs(xs, ys):
dacp = DelayedAcp(10)
for tick in zip(range(len(xs)), xs, ys):
dacp(tick)
return dacp.lows, dacp.highs
class DelayedAcp:
"""Time series max & min detector."""
def __init__(self, bias):
assert(bias > 0)
self.bias = bias
self.trend = None
self.mm0 = None
self.lohis = [ ]
self.lows = [ ]
self.highs = [ ]
def __call__(self, tick):
"""Add extended tick to the max min parser.
@param tick: The value of the current tick.
@type tick: tuple(n, cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
# automatic initialisation
if self.mm0 is None:
# initalise water mark
self.mm0 = tick
res = self.mm0
self.lows = [(n, cdt, last - 1)]
self.highs = [(n, cdt, last + 1)]
else:
# initalise trend until price has changed
if self.trend is None or self.trend == 0:
self.trend = cmp(last, self.mm0[2])
# check for max
if self.trend > 0:
if last > self.mm0[2]:
self.mm0 = tick
if last < self.mm0[2] - self.bias:
self.lohis.append(self.mm0)
self.highs.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = -1
# check for min
if self.trend < 0:
if last < self.mm0[2]:
self.mm0 = tick
if last > self.mm0[2] + self.bias:
self.lohis.append(self.mm0)
self.lows.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = +1
return (cmp(self.trend, 0), res)
class Main:
def __init__(self):
warnings.simplefilter("default", np.RankWarning)
self.ylow = None
self.yhigh = None
self.advance_count = 1
self.root = Tk.Tk()
self.root.wm_title("Embedding in TK")
# create plot
fig = plt.figure()
self.ax1 = fig.add_subplot(211) # ticks
self.ax2 = fig.add_subplot(212) # diff from polyfit
# ax3 = fig.add_subplot(313) # cash
self.ax1.set_ylabel("ticks")
self.ax2.set_ylabel("polyfit diff")
# ax3.set_ylabel("cash")
major_fmt = mdates.DateFormatter('%H:%M:%S')
self.ax1.xaxis.set_major_formatter(major_fmt)
self.ax1.format_xdata = major_fmt
self.ax1.format_ydata = lambda x: '%1.2f' % x
self.ax1.grid(True)
self.ax2.xaxis.set_major_formatter(major_fmt)
self.ax2.format_xdata = major_fmt
self.ax2.format_ydata = lambda x: '%1.2f' % x
self.ax2.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
# create artists
LOG.debug("Loading ticks...")
self.x, self.y = tdl(datetime.datetime(2009, 6, 3))
LOG.debug("Ticks loaded.")
lows, highs = find_lows_highs(self.x, self.y)
self.mmh = Lohi(10)
self.w0 = 0
self.wd = 1000
self.low_high_crs = 0
xr, yr = self.tick_window(self.w0, self.wd)
fit = np.average(yr)
self.tl, = self.ax1.plot_date(xr, yr, '-')
self.fl, = self.ax1.plot_date(xr, (fit,) * len(xr), 'k--')
self.mh, = self.ax1.plot_date(xr, (yr[0],) * len(xr), 'g:')
self.ml, = self.ax1.plot_date(xr, (yr[0],) * len(xr), 'r:')
self.him, = self.ax1.plot_date([x for n, x, y in lows], [y for n, x, y in lows], 'go')
self.lom, = self.ax1.plot_date([x for n, x, y in highs], [y for n, x, y in highs], 'ro')
self.dl, = self.ax2.plot_date(xr, (0,) * len(xr), '-')
self.set_axis(xr, yr)
# embed canvas in Tk
self.canvas = FigureCanvasTkAgg(fig, master=self.root)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=Tk.TRUE)
# toolbar = NavigationToolbar2TkAgg( self.canvas, self.root )
# toolbar.update()
# self.canvas._tkself.canvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
fr1 = Tk.Frame(master=self.root)
bu1 = Tk.Button(master=fr1, text='Quit', command=self.root.quit)
bu2 = Tk.Button(master=fr1, text='Stop', command=self.stop)
bu3 = Tk.Button(master=fr1, text='Resume', command=self.resume)
bu4 = Tk.Button(master=fr1, text='1x', command=self.times_one)
bu5 = Tk.Button(master=fr1, text='5x', command=self.times_five)
bu6 = Tk.Button(master=fr1, text='10x', command=self.times_ten)
bu1.pack(side=Tk.RIGHT, padx=5, pady=5)
bu6.pack(side=Tk.RIGHT, padx=5, pady=5)
bu5.pack(side=Tk.RIGHT, padx=5, pady=5)
bu4.pack(side=Tk.RIGHT, padx=5, pady=5)
bu2.pack(side=Tk.RIGHT, padx=5, pady=5)
bu3.pack(side=Tk.RIGHT, padx=5, pady=5)
fr1.pack(side=Tk.BOTTOM)
def animate(self):
self.w0 += self.advance_count
# prepare timeline window
xr, yr = self.tick_window(self.w0, self.wd)
while self.low_high_crs < self.w0 + self.wd:
self.mark_low_high(self.low_high_crs)
self.low_high_crs += 1
# build polynomial fit
mms = self.mmh.lohis
if len(mms) > 1:
mx = [ (x - int(x)) * 86400 for x in xr ]
my = yr
polyval = np.polyfit(mx, my, 10)
fit = np.polyval(polyval, mx)
self.fl.set_data(xr, fit)
# calc diff
self.dl.set_data(xr, yr - fit)
maxs = self.mmh.highs
if len(maxs) > 1:
n, x1, y1 = maxs[-2]
n, x2, y2 = maxs[-1]
x3 = xr[-1]
polyfit = np.polyfit((x1, x2), (y1, y2), 1)
y3 = np.polyval(polyfit, x3)
self.mh.set_data((x1, x2, x3), (y1, y2, y3))
mins = self.mmh.lows
if len(mins) > 1:
n, x1, y1 = mins[-2]
n, x2, y2 = mins[-1]
x3 = xr[-1]
polyfit = np.polyfit((x1, x2), (y1, y2), 1)
y3 = np.polyval(polyfit, x3)
self.ml.set_data((x1, x2, x3), (y1, y2, y3))
# update tick line
self.tl.set_data(xr, yr)
# update axis
self.set_axis(xr, yr)
self.canvas.draw()
if self.w0 < len(self.x) - self.wd - 1:
self.after_id = self.root.after(10, self.animate)
def set_axis(self, xr, yr, bias=50):
if self.ylow is None:
self.ylow = yr[0] - bias / 2
self.yhigh = yr[0] + bias / 2
for y in yr:
if y < self.ylow:
self.ylow = y
self.yhigh = self.ylow + bias
if y > self.yhigh:
self.yhigh = y
self.ylow = self.yhigh - bias
self.ax1.axis([xr[0], xr[-1], self.ylow, self.yhigh])
self.ax2.axis([xr[0], xr[-1], -25, +25])
def tick_window(self, w0, wd=1000):
return (self.x[w0:w0 + wd], self.y[w0:w0 + wd])
def mark_low_high(self, n):
x = self.x
y = self.y
rc = self.mmh((n, x[n], y[n]))
if rc:
lohi, tick = rc
nlh, xlh, ylh = tick
if lohi < 0:
# low
self.ax1.annotate('low',
xy=(x[nlh], y[nlh]),
xytext=(x[n], y[nlh]),
arrowprops=dict(facecolor='red',
frac=0.3,
shrink=0.1))
elif lohi > 0:
# high
self.ax1.annotate('high',
xy=(x[nlh], y[nlh]),
xytext=(x[n], y[nlh]),
arrowprops=dict(facecolor='green',
frac=0.3,
shrink=0.1))
def stop(self):
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
def resume(self):
if self.after_id is None:
self.after_id = self.root.after(10, self.animate)
def times_one(self):
self.advance_count = 1
def times_five(self):
self.advance_count = 5
def times_ten(self):
self.advance_count = 10
def run(self):
self.root.after(500, self.animate)
self.root.mainloop()
self.root.destroy()
if __name__ == "__main__":
app = Main()
app.run()

444
mpl/fibionacci2.py Normal file
View File

@@ -0,0 +1,444 @@
# Copyright (c) 2008 Andreas Balogh
# See LICENSE for details.
""" animated drawing of ticks
using self.canvas embedded in Tk application
Fibionacci retracements of 61.8, 50.0, 38.2, 23.6 % of min and max
"""
# system imports
import datetime
import os
import re
import logging
import warnings
import math
import Tkinter as Tk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num
# local imports
# constants
ONE_MINUTE = 60. / 86400.
LOW, NONE, HIGH = range(-1, 2)
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
MDF_REO = re.compile("(..):(..):(..)\.*(\d+)*")
def tdl(tick_date):
""" returns a list of tick tuples (cdt, last) for specified day """
fiid = "846900"
year = tick_date.strftime("%Y")
yyyymmdd = tick_date.strftime("%Y%m%d")
filename = "%s.csv" % (fiid)
filepath = os.path.join("c:\\rttrd-prd-var\\consors-mdf\\data", year, yyyymmdd, filename)
x = [ ]
y = [ ]
fh = open(filepath, "r")
try:
prev_last = ""
for line in fh:
flds = line.split(",")
# determine file version
if flds[2] == "LAST":
last = float(flds[3])
vol = float(flds[4])
else:
last = float(flds[4])
vol = 0.0
# skip ticks with same last price
if prev_last == last:
continue
else:
prev_last = last
# parse time
mobj = MDF_REO.match(flds[0])
if mobj is None:
raise ValueError("no match for [%s]" % (flds[0],))
(hh, mm, ss, ms) = mobj.groups()
if ms:
c_time = datetime.time(int(hh), int(mm), int(ss), int(ms) * 1000)
else:
c_time = datetime.time(int(hh), int(mm), int(ss))
cdt = datetime.datetime.combine(tick_date, c_time)
x.append(date2num(cdt))
y.append(last)
finally:
fh.close()
# throw away first line of file (close price from previous day)
del x[0]
del y[0]
return (x, y)
def num2sod(x):
frac, integ = math.modf(x)
return frac * 86400
class Lohi:
"""Time series online low and high detector."""
def __init__(self, bias):
assert(bias > 0)
self.bias = bias
self.low0 = None
self.high0 = None
self.prev_lohi = NONE
self.lohis = [ ]
self.lows = [ ]
self.highs = [ ]
def __call__(self, tick):
"""Add extended tick to the max min parser.
@param tick: The value of the current tick.
@type tick: tuple(cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
# automatic initialisation
if self.low0 is None:
self.low0 = tick
self.lows.append((n, cdt, last - 1))
if self.high0 is None:
self.high0 = tick
self.highs.append((n, cdt, last + 1))
if last > self.high0[2]:
self.high0 = tick
if self.prev_lohi == NONE:
if self.high0[2] > self.low0[2] + self.bias:
res = self.high0
self.low0 = self.high0
self.lows.append(self.high0)
self.lohis.append(self.high0)
self.prev_lohi = HIGH
if last < self.low0[2]:
self.low0 = tick
if self.prev_lohi == NONE:
if self.low0[2] < self.high0[2] - self.bias:
res = self.low0
self.high0 = self.low0
self.lows.append(self.low0)
self.lohis.append(self.low0)
self.prev_lohi = LOW
if self.high0[1] < cdt - ONE_MINUTE and \
((self.prev_lohi == LOW and \
self.high0[2] > self.lows[-1][2] + self.bias) or
(self.prev_lohi == HIGH and \
self.high0[2] > self.highs[-1][2])):
res = self.high0
self.low0 = self.high0
self.highs.append(self.high0)
self.lohis.append(self.high0)
self.prev_lohi = HIGH
if self.low0[1] < cdt - ONE_MINUTE and \
((self.prev_lohi == LOW and \
self.low0[2] < self.lows[-1][2]) or
(self.prev_lohi == HIGH and \
self.low0[2] < self.highs[-1][2] - self.bias)):
res = self.low0
self.high0 = self.low0
self.lows.append(self.low0)
self.lohis.append(self.low0)
self.prev_lohi = LOW
if res:
return (self.prev_lohi, res)
else:
return None
class Acp:
"""Always correct predictor"""
def __init__(self, lows, highs):
self.lows = lows
self.highs = highs
def __call__(self, tick):
"""Always correct predictor.
Requires previous run of DelayedAcp to determine lows and highs.
@param tick: The value of the current tick.
@type tick: tuple(n, cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
return res
def find_lows_highs(xs, ys):
dacp = DelayedAcp(10)
for tick in zip(range(len(xs)), xs, ys):
dacp(tick)
return dacp.lows, dacp.highs
class DelayedAcp:
"""Time series max & min detector."""
def __init__(self, bias):
assert(bias > 0)
self.bias = bias
self.trend = None
self.mm0 = None
self.lohis = [ ]
self.lows = [ ]
self.highs = [ ]
def __call__(self, tick):
"""Add extended tick to the max min parser.
@param tick: The value of the current tick.
@type tick: tuple(n, cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
# automatic initialisation
if self.mm0 is None:
# initalise water mark
self.mm0 = tick
res = self.mm0
self.lows = [(n, cdt, last - 1)]
self.highs = [(n, cdt, last + 1)]
else:
# initalise trend until price has changed
if self.trend is None or self.trend == 0:
self.trend = cmp(last, self.mm0[2])
# check for max
if self.trend > 0:
if last > self.mm0[2]:
self.mm0 = tick
if last < self.mm0[2] - self.bias:
self.lohis.append(self.mm0)
self.highs.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = -1
# check for min
if self.trend < 0:
if last < self.mm0[2]:
self.mm0 = tick
if last > self.mm0[2] + self.bias:
self.lohis.append(self.mm0)
self.lows.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = +1
return (cmp(self.trend, 0), res)
class Main:
def __init__(self):
warnings.simplefilter("default", np.RankWarning)
self.ylow = None
self.yhigh = None
self.advance_count = 1
self.root = Tk.Tk()
self.root.wm_title("Embedding in TK")
# create plot
fig = plt.figure()
self.ax1 = fig.add_subplot(211) # ticks
self.ax2 = fig.add_subplot(212) # diff from polyfit
# ax3 = fig.add_subplot(313) # cash
self.ax1.set_ylabel("ticks")
self.ax2.set_ylabel("polyfit diff")
# ax3.set_ylabel("cash")
major_fmt = mdates.DateFormatter('%H:%M:%S')
self.ax1.xaxis.set_major_formatter(major_fmt)
self.ax1.format_xdata = major_fmt
self.ax1.format_ydata = lambda x: '%1.2f' % x
self.ax1.grid(True)
self.ax2.xaxis.set_major_formatter(major_fmt)
self.ax2.format_xdata = major_fmt
self.ax2.format_ydata = lambda x: '%1.2f' % x
self.ax2.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
# create artists
LOG.debug("Loading ticks...")
self.x, self.y = tdl(datetime.datetime(2009, 6, 3))
LOG.debug("Ticks loaded.")
lows, highs = find_lows_highs(self.x, self.y)
self.mmh = Lohi(10)
self.w0 = 0
self.wd = 1000
self.low_high_crs = 0
xr, yr = self.tick_window(self.w0, self.wd)
fit = np.average(yr)
self.tl, = self.ax1.plot_date(xr, yr, '-')
self.fl, = self.ax1.plot_date(xr, (fit,) * len(xr), 'k--')
self.mh, = self.ax1.plot_date(xr, (yr[0],) * len(xr), 'g:')
self.ml, = self.ax1.plot_date(xr, (yr[0],) * len(xr), 'r:')
self.him, = self.ax1.plot_date([x for n, x, y in lows], [y for n, x, y in lows], 'go')
self.lom, = self.ax1.plot_date([x for n, x, y in highs], [y for n, x, y in highs], 'ro')
self.dl, = self.ax2.plot_date(xr, (0,) * len(xr), '-')
self.set_axis(xr, yr)
# embed canvas in Tk
self.canvas = FigureCanvasTkAgg(fig, master=self.root)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=Tk.TRUE)
# toolbar = NavigationToolbar2TkAgg( self.canvas, self.root )
# toolbar.update()
# self.canvas._tkself.canvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
fr1 = Tk.Frame(master=self.root)
bu1 = Tk.Button(master=fr1, text='Quit', command=self.root.quit)
bu2 = Tk.Button(master=fr1, text='Stop', command=self.stop)
bu3 = Tk.Button(master=fr1, text='Resume', command=self.resume)
bu4 = Tk.Button(master=fr1, text='1x', command=self.times_one)
bu5 = Tk.Button(master=fr1, text='5x', command=self.times_five)
bu6 = Tk.Button(master=fr1, text='10x', command=self.times_ten)
bu1.pack(side=Tk.RIGHT, padx=5, pady=5)
bu6.pack(side=Tk.RIGHT, padx=5, pady=5)
bu5.pack(side=Tk.RIGHT, padx=5, pady=5)
bu4.pack(side=Tk.RIGHT, padx=5, pady=5)
bu2.pack(side=Tk.RIGHT, padx=5, pady=5)
bu3.pack(side=Tk.RIGHT, padx=5, pady=5)
fr1.pack(side=Tk.BOTTOM)
def animate(self):
self.w0 += self.advance_count
# prepare timeline window
xr, yr = self.tick_window(self.w0, self.wd)
while self.low_high_crs < self.w0 + self.wd:
self.mark_low_high(self.low_high_crs)
self.low_high_crs += 1
# build polynomial fit
mms = self.mmh.lohis
if len(mms) > 1:
mx = [ num2sod(x) for x in xr ]
my = yr
polyval = np.polyfit(mx, my, 10)
fit = np.polyval(polyval, mx)
self.fl.set_data(xr, fit)
# calc diff
self.dl.set_data(xr, yr - fit)
highs = self.mmh.highs
if len(highs) >= 4:
coefs = np.polyfit([num2sod(x) for n, x, y in highs[-4:]], [y for n, x, y in highs[-4:]], 3)
self.mh.set_data(xr, [np.polyval(coefs, num2sod(x)) for x in xr])
lows = self.mmh.lows
if len(lows) >= 4:
coefs = np.polyfit([num2sod(x) for n, x, y in lows[-4:]], [y for n, x, y in lows[-4:]], 3)
self.ml.set_data(xr, [np.polyval(coefs, num2sod(x)) for x in xr])
# update tick line
self.tl.set_data(xr, yr)
# update axis
self.set_axis(xr, yr)
self.canvas.draw()
if self.w0 < len(self.x) - self.wd - 1:
self.after_id = self.root.after(10, self.animate)
def set_axis(self, xr, yr, bias=50):
if self.ylow is None:
self.ylow = yr[0] - bias / 2
self.yhigh = yr[0] + bias / 2
for y in yr:
if y < self.ylow:
self.ylow = y
self.yhigh = self.ylow + bias
if y > self.yhigh:
self.yhigh = y
self.ylow = self.yhigh - bias
self.ax1.axis([xr[0], xr[-1], self.ylow, self.yhigh])
self.ax2.axis([xr[0], xr[-1], -25, +25])
def tick_window(self, w0, wd = 1000):
return (self.x[w0:w0 + wd], self.y[w0:w0 + wd])
def mark_low_high(self, n):
x = self.x
y = self.y
rc = self.mmh((n, x[n], y[n]))
if rc:
lohi, tick = rc
nlh, xlh, ylh = tick
if lohi < 0:
# low
self.ax1.annotate('low',
xy=(x[nlh], y[nlh]),
xytext=(x[n], y[nlh]),
arrowprops=dict(facecolor='red',
frac=0.3,
shrink=0.1))
elif lohi > 0:
# high
self.ax1.annotate('high',
xy=(x[nlh], y[nlh]),
xytext=(x[n], y[nlh]),
arrowprops=dict(facecolor='green',
frac=0.3,
shrink=0.1))
def stop(self):
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
def resume(self):
if self.after_id is None:
self.after_id = self.root.after(10, self.animate)
def times_one(self):
self.advance_count = 1
def times_five(self):
self.advance_count = 5
def times_ten(self):
self.advance_count = 10
def run(self):
self.root.after(500, self.animate)
self.root.mainloop()
self.root.destroy()
if __name__ == "__main__":
app = Main()
app.run()

174
mpl/mpl-blit.py Normal file
View File

@@ -0,0 +1,174 @@
# Copyright (c) 2009 Andreas Balogh
# See LICENSE for details.
""" animated drawing of ticks
using blit method
"""
# system imports
import Tkinter as tk
import datetime
import os
import re
import logging
import sys
import matplotlib.pyplot as plt
from matplotlib.dates import date2num
import matplotlib.dates as mdates
import numpy as np
# local imports
# constants
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
MDF_REO = re.compile("(..):(..):(..)\.*(\d+)*")
def tdl(tick_date):
""" returns a list of tick tuples (cdt, last) for specified day """
fiid = "846900"
year = tick_date.strftime("%Y")
yyyymmdd = tick_date.strftime("%Y%m%d")
filename = "%s.csv" % (fiid)
filepath = os.path.join("d:\\rttrd-prd-var\\consors-mdf\\data", year, yyyymmdd, filename)
x = [ ]
y = [ ]
fh = open(filepath, "r")
try:
prev_last = ""
for line in fh:
flds = line.split(",")
# determine file version
if flds[2] == "LAST":
last = float(flds[3])
vol = float(flds[4])
else:
last = float(flds[4])
vol = 0.0
# skip ticks with same last price
if prev_last == last:
continue
else:
prev_last = last
# parse time
mobj = MDF_REO.match(flds[0])
if mobj is None:
raise ValueError("no match for [%s]" % (flds[0],))
(hh, mm, ss, ms) = mobj.groups()
if ms:
c_time = datetime.time(int(hh), int(mm), int(ss), int(ms) * 1000)
else:
c_time = datetime.time(int(hh), int(mm), int(ss))
cdt = datetime.datetime.combine(tick_date, c_time)
x.append(date2num(cdt))
y.append(last)
finally:
fh.close()
# throw away first line of file (close price from previous day)
del x[0]
del y[0]
return (x, y)
def main():
LOG.debug("Loading ticks...")
x, y = tdl(datetime.datetime(2009,6,3))
LOG.debug("Ticks loaded.")
fig = plt.figure()
ax1 = fig.add_subplot(311) # ticks
canvas = ax1.figure.canvas
# ax2 = fig.add_subplot(312) # gearing
# ax3 = fig.add_subplot(313) # cash
ax1.set_ylabel("ticks")
# ax2.set_ylabel("gearing")
# ax3.set_ylabel("cash")
xr = [x[0]] * 500
yr = [y[0]] * 500
line, = ax1.plot_date(xr, yr, '-', xdate = True)
major_fmt = mdates.DateFormatter('%H:%M:%S')
ax1.xaxis.set_major_formatter(major_fmt)
# ax1.axis('tight')
# format the coords message box
def price(x): return '%1.2f'%x
# ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')
ax1.format_xdata = mdates.DateFormatter('%H:%M:%S')
ax1.format_ydata = price
ax1.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
background = canvas.copy_from_bbox(ax1.bbox)
def animate():
w = 1000
bias = 10
ymin = min(y[0:100])
ymax = max(y[0:100])
low = ymin - bias
high = ymax + bias
trend = 0
for i in range(0, len(x)-w):
# restore the clean slate background
canvas.restore_region(background)
# prepare timeline window
xr = x[i:i+w]
yr = y[i:i+w]
# update line
line.set_xdata(xr)
line.set_ydata(yr)
# determine y axis
if yr[-1] > ymax:
ymax = yr[-1]
if ymax - 50 < min(yr):
ymin = ymax - 50
if yr[-1] < ymin:
ymin = yr[-1]
if ymin + 50 > max(yr):
ymax = ymin + 50
ax1.axis([xr[0], xr[-1], ymin, ymax])
# check low high and annotate
if i > 0 and i % 150 == 0:
ax1.annotate('low/high',
xy = (xr[-10], yr[-10]),
xytext = (xr[-5], yr[-10] + 10),
arrowprops = dict(facecolor = 'black',
frac = 0.2,
headwidth = 10,
linewidth = 0.1,
shrink = 0.05))
# just draw the animated artist
# FIXME: redraw all items in graph
ax1.draw_artist(line)
# just redraw the axes rectangle
canvas.blit(ax1.bbox)
root = fig.canvas.manager.window
root.after(100, animate)
plt.show()
if __name__ == "__main__":
main()

163
mpl/mpl-draw.py Normal file
View File

@@ -0,0 +1,163 @@
# Copyright (c) 2008 Andreas Balogh
# See LICENSE for details.
""" animated drawing of ticks
using draw method
"""
# system imports
import Tkinter as tk
import datetime
import os
import re
import logging
import sys
import matplotlib.pyplot as plt
from matplotlib.dates import date2num
import matplotlib.dates as mdates
import numpy as np
# local imports
# constants
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
MDF_REO = re.compile("(..):(..):(..)\.*(\d+)*")
def tdl(tick_date):
""" returns a list of tick tuples (cdt, last) for specified day """
fiid = "846900"
year = tick_date.strftime("%Y")
yyyymmdd = tick_date.strftime("%Y%m%d")
filename = "%s.csv" % (fiid)
filepath = os.path.join("d:\\rttrd-prd-var\\consors-mdf\\data", year, yyyymmdd, filename)
x = [ ]
y = [ ]
fh = open(filepath, "r")
try:
prev_last = ""
for line in fh:
flds = line.split(",")
# determine file version
if flds[2] == "LAST":
last = float(flds[3])
vol = float(flds[4])
else:
last = float(flds[4])
vol = 0.0
# skip ticks with same last price
if prev_last == last:
continue
else:
prev_last = last
# parse time
mobj = MDF_REO.match(flds[0])
if mobj is None:
raise ValueError("no match for [%s]" % (flds[0],))
(hh, mm, ss, ms) = mobj.groups()
if ms:
c_time = datetime.time(int(hh), int(mm), int(ss), int(ms) * 1000)
else:
c_time = datetime.time(int(hh), int(mm), int(ss))
cdt = datetime.datetime.combine(tick_date, c_time)
x.append(date2num(cdt))
y.append(last)
finally:
fh.close()
# throw away first line of file (close price from previous day)
del x[0]
del y[0]
return (x, y)
def main():
LOG.debug("Loading ticks...")
x, y = tdl(datetime.datetime(2009,6,3))
LOG.debug("Ticks loaded.")
fig = plt.figure()
ax1 = fig.add_subplot(311) # ticks
# ax2 = fig.add_subplot(312) # gearing
# ax3 = fig.add_subplot(313) # cash
ax1.set_ylabel("ticks")
# ax2.set_ylabel("gearing")
# ax3.set_ylabel("cash")
xr = [x[0]] * 500
yr = [y[0]] * 500
line, = ax1.plot_date(xr, yr, '-', xdate = True)
major_fmt = mdates.DateFormatter('%H:%M:%S')
ax1.xaxis.set_major_formatter(major_fmt)
# ax1.axis('tight')
# format the coords message box
def price(x): return '%1.2f'%x
# ax.format_xdata = mdates.DateFormatter('%Y-%m-%d')
ax1.format_xdata = mdates.DateFormatter('%H:%M:%S')
ax1.format_ydata = price
ax1.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
def animate():
w = 1000
bias = 10
ymin = min(y[0:100])
ymax = max(y[0:100])
low = ymin - bias
high = ymax + bias
trend = 0
for i in range(0, len(x)-w):
# prepare timeline window
xr = x[i:i+w]
yr = y[i:i+w]
# update line
line.set_xdata(xr)
line.set_ydata(yr)
# determine y axis
if yr[-1] > ymax:
ymax = yr[-1]
if ymax - 50 < min(yr):
ymin = ymax - 50
if yr[-1] < ymin:
ymin = yr[-1]
if ymin + 50 > max(yr):
ymax = ymin + 50
ax1.axis([xr[0], xr[-1], ymin, ymax])
# check low high and annotate
if i > 0 and i % 150 == 0:
ax1.annotate('low/high',
xy = (xr[-10], yr[-10]),
xytext = (xr[-5], yr[-10] + 10),
arrowprops = dict(facecolor = 'black',
frac = 0.2,
headwidth = 10,
linewidth = 0.1,
shrink = 0.05))
fig.canvas.draw()
root = fig.canvas.manager.window
root.after(100, animate)
plt.show()
if __name__ == "__main__":
main()

330
mpl/mpl-embedded.py Normal file
View File

@@ -0,0 +1,330 @@
# Copyright (c) 2008 Andreas Balogh
# See LICENSE for details.
""" animated drawing of ticks
using self.canvas embedded in Tk application
Fibionacci retracements of 61.8, 50.0, 38.2, 23.6 % of min and max
"""
# system imports
import datetime
import os
import re
import logging
import sys
import warnings
import Tkinter as Tk
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import date2num
# local imports
# constants
# globals
LOG = logging.getLogger()
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03i %(levelname).4s %(process)d:%(thread)d %(message)s',
datefmt='%H:%M:%S')
MDF_REO = re.compile("(..):(..):(..)\.*(\d+)*")
def tdl(tick_date):
""" returns a list of tick tuples (cdt, last) for specified day """
fiid = "846900"
year = tick_date.strftime("%Y")
yyyymmdd = tick_date.strftime("%Y%m%d")
filename = "%s.csv" % (fiid)
filepath = os.path.join("d:\\rttrd-prd-var\\consors-mdf\\data", year, yyyymmdd, filename)
x = [ ]
y = [ ]
fh = open(filepath, "r")
try:
prev_last = ""
for line in fh:
flds = line.split(",")
# determine file version
if flds[2] == "LAST":
last = float(flds[3])
vol = float(flds[4])
else:
last = float(flds[4])
vol = 0.0
# skip ticks with same last price
if prev_last == last:
continue
else:
prev_last = last
# parse time
mobj = MDF_REO.match(flds[0])
if mobj is None:
raise ValueError("no match for [%s]" % (flds[0],))
(hh, mm, ss, ms) = mobj.groups()
if ms:
c_time = datetime.time(int(hh), int(mm), int(ss), int(ms) * 1000)
else:
c_time = datetime.time(int(hh), int(mm), int(ss))
cdt = datetime.datetime.combine(tick_date, c_time)
x.append(date2num(cdt))
y.append(last)
finally:
fh.close()
# throw away first line of file (close price from previous day)
del x[0]
del y[0]
return (x, y)
class Mmh:
"""Time series max & min detector."""
def __init__(self, bias):
assert(bias > 0)
self.bias = bias
self.trend = None
self.mm0 = None
self.mms = [ ]
self.mins = [ ]
self.maxs = [ ]
def __call__(self, tick):
"""Add extended tick to the max min parser.
@param tick: The value of the current tick.
@type tick: tuple(cdt, last)
@return: 1. Tick if new max min has been detected,
2. None otherwise.
"""
n, cdt, last = tick
res = None
# automatic initialisation
if self.mm0 is None:
# initalise water mark
self.mm0 = tick
res = self.mm0
self.mins = [(n, cdt, last - 1)]
self.maxs = [(n, cdt, last + 1)]
else:
# initalise trend until price has changed
if self.trend is None or self.trend == 0:
self.trend = cmp(last, self.mm0[2])
# check for max
if self.trend > 0:
if last > self.mm0[2]:
self.mm0 = tick
if last < self.mm0[2] - self.bias:
self.mms.insert(0, self.mm0)
self.maxs.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = -1
# check for min
if self.trend < 0:
if last < self.mm0[2]:
self.mm0 = tick
if last > self.mm0[2] + self.bias:
self.mms.insert(0, self.mm0)
self.mins.append(self.mm0)
res = self.mm0
# revert trend & water mark
self.mm0 = tick
self.trend = +1
return res
class Main:
def __init__(self):
LOG.debug("Loading ticks...")
self.x, self.y = tdl(datetime.datetime(2009,6,3))
LOG.debug("Ticks loaded.")
self.mmh = Mmh(10)
self.root = Tk.Tk()
self.root.wm_title("Embedding in TK")
fig = plt.figure()
self.ax1 = fig.add_subplot(111) # ticks
# ax2 = fig.add_subplot(312) # gearing
# ax3 = fig.add_subplot(313) # cash
self.ax1.set_ylabel("ticks")
# ax2.set_ylabel("gearing")
# ax3.set_ylabel("cash")
self.w = 1000
self.bias = 10
xr = self.x[0:self.w]
yr = self.y[0:self.w]
fit = np.average(yr)
self.tl, = self.ax1.plot_date(xr, yr, '-')
self.fl, = self.ax1.plot_date(xr, (fit, ) * self.w, 'k--')
self.mh, = self.ax1.plot_date(xr, (yr[0], ) * self.w, 'g:')
self.ml, = self.ax1.plot_date(xr, (yr[0], ) * self.w, 'r:')
major_fmt = mdates.DateFormatter('%H:%M:%S')
self.ax1.xaxis.set_major_formatter(major_fmt)
self.ax1.format_xdata = mdates.DateFormatter('%H:%M:%S')
self.ax1.format_ydata = lambda x: '%1.2f'%x
self.ax1.grid(True)
# rotates and right aligns the x labels, and moves the bottom of the
# axes up to make room for them
fig.autofmt_xdate()
self.ax1.axis([xr[0], xr[-1]+180./86400., min(yr), max(yr)])
self.canvas = FigureCanvasTkAgg(fig, master=self.root)
self.canvas.draw()
self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
# toolbar = NavigationToolbar2TkAgg( self.canvas, self.root )
# toolbar.update()
# self.canvas._tkself.canvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
fr1 = Tk.Frame(master = self.root)
bu1 = Tk.Button(master = fr1, text='Quit', command=self.root.quit)
bu2 = Tk.Button(master = fr1, text='Stop', command=self.stop)
bu3 = Tk.Button(master = fr1, text='Resume', command=self.resume)
bu1.pack(side = Tk.RIGHT, padx = 5, pady = 5)
bu2.pack(side = Tk.RIGHT, padx = 5, pady = 5)
bu3.pack(side = Tk.RIGHT, padx = 5, pady = 5)
fr1.pack(side = Tk.BOTTOM)
def animate_start(self):
warnings.simplefilter("default", np.RankWarning)
self.ymin = min(self.y[0:self.w])
self.ymax = max(self.y[0:self.w])
self.low = self.ymin - self.bias
self.high = self.ymax + self.bias
self.trend = 0
self.i = 0
for n in range(0, self.w):
self.mark_low_high(n)
self.root.after(500, self.animate_step)
def animate_step(self):
# prepare timeline window
xr = np.array( self.x[self.i:self.i+self.w] )
yr = np.array( self.y[self.i:self.i+self.w] )
# update line
self.tl.set_xdata(xr)
self.tl.set_ydata(yr)
# determine y axis
if yr[-1] > self.ymax:
self.ymax = yr[-1]
if self.ymax - 50 < min(yr):
self.ymin = self.ymax - 50
if yr[-1] < self.ymin:
self.ymin = yr[-1]
if self.ymin + 50 > max(yr):
self.ymax = self.ymin + 50
# check self.low self.high and annotate
fwd = 2
for n in range(self.i+self.w, self.i+self.w+fwd):
self.mark_low_high(n)
self.i += fwd
# build polynomial fit
mms = self.mmh.mms
if len(mms) > 1:
# mx = [ (x - int(x)) * 86400 for n, x, y in mms[:4] ]
# my = [ y for n, x, y in mms[:4] ]
mx = [ (x - int(x)) * 86400 for x in xr ]
my = yr
xre = [ xr[-1] + x/86400. for x in range(1, 181)]
xr2 = np.append(xr, xre)
# print "mx: ", mx
# print "my: ", my
polyval = np.polyfit(mx, my, 30)
# print "poly1d: ", polyval
intx = np.array(xr, dtype = int)
sodx = xr - intx
sodx *= 86400
s2x = np.append(sodx, range(sodx[-1], sodx[-1]+180))
fit = np.polyval(polyval, s2x)
self.fl.set_xdata(xr2)
self.fl.set_ydata(fit)
maxs = self.mmh.maxs
if len(maxs) > 1:
n, x1, y1 = maxs[-2]
n, x2, y2 = maxs[-1]
x3 = xr[-1]
polyfit = np.polyfit((x1, x2), (y1, y2), 1)
y3 = np.polyval(polyfit, x3)
self.mh.set_data((x1, x2, x3), (y1, y2, y3))
mins = self.mmh.mins
if len(mins) > 1:
n, x1, y1 = mins[-2]
n, x2, y2 = mins[-1]
x3 = xr[-1]
polyfit = np.polyfit((x1, x2), (y1, y2), 1)
y3 = np.polyval(polyfit, x3)
self.ml.set_data((x1, x2, x3), (y1, y2, y3))
# draw
self.ax1.axis([xr[0], xr[-1]+180./86400., self.ymin, self.ymax])
self.canvas.draw()
if self.i < len(self.x)-self.w-1:
self.after_id = self.root.after(10, self.animate_step)
def build_fit(self):
pass
def mark_low_high(self, n):
x = self.x
y = self.y
rc = self.mmh((n, x[n], y[n]))
if rc:
nlh, xlh, ylh = rc
if self.mmh.trend > 0:
# low
self.ax1.annotate('low',
xy = (x[nlh], y[nlh]),
xytext = (x[n], y[nlh]),
arrowprops = dict(facecolor = 'red',
shrink = 0.05))
# an.set_annotation_clip(True)
elif self.mmh.trend < 0:
# high
self.ax1.annotate('high',
xy = (x[nlh], y[nlh]),
xytext = (x[n], y[nlh]),
arrowprops = dict(facecolor = 'green',
shrink = 0.05))
# an.set_annotation_clip(True)
def stop(self):
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
def resume(self):
if self.after_id is None:
self.after_id = self.root.after(10, self.animate_step)
def run(self):
self.root.after(500, self.animate_start)
self.root.mainloop()
self.root.destroy()
if __name__ == "__main__":
app = Main()
app.run()

62
src/batch_rename.py Normal file
View File

@@ -0,0 +1,62 @@
""" flatex broker server """
import getopt
import sys
import os
import re
import logging
mylog = logging.getLogger('batch_rename')
class Usage(Exception):
def __init__(self, message):
Exception.__init__(message)
class Error(Exception):
def __init__(self, message):
Exception.__init__(message)
# Star.Trek.The.Next.Generation.1x01-02.Encounter.At.Farpoint.DVDRip-AMC.[tvu.org.ru].avi
# Star Trek TNG - 1x01-2 - Encounter At Farpoint - DVDRip-AMC.divx.avi
def main(argv = None):
if argv == None:
argv = sys.argv
mylog.info("starting [%s]" % (argv[0],))
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
print "opts: ", opts, "args:", args
except getopt.error, msg:
raise Usage(msg)
# more code, unchanged
p = re.compile("Star\.Trek\.The\.Next\.Generation.(.*?)\.(.*)\.(DVDRip-.*)\.\[tvu.org.ru\]\.avi")
tng = "e:\\share\\movies\\star trek tng"
os.chdir(tng)
for (dirpath, dirnames, filenames) in os.walk(tng):
for f in filenames:
mot = re.match(p, f)
if mot is not None:
# print mot.group()
print mot.groups()
ver = mot.group(1)
title0 = mot.group(2)
title1 = title0.replace('.', ' ')
nf = "Star Trek TNG - %s - %s - %s.divx.avi" % (ver, title1, mot.group(3))
# os.rename(f, nf)
print 'ren "%s" "%s"' % (f, nf)
except Error, err:
mylog.error(err.message)
return 1
except Usage, err:
mylog.error(err.message)
mylog.error("for help use --help")
return 2
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
datefmt='%H:%M:%S')
sys.exit(main())

6
src/ftpget.py Normal file
View File

@@ -0,0 +1,6 @@
from ftplib import FTP
ftp = FTP('ftp.asstr.org') # connect to host, default port
ftp.login() # user anonymous, passwd anonymous@
print ftp.getwelome()
ftp.retrbinary('RETR README', open('README', 'wb').write)

97
src/histogram.py Normal file
View File

@@ -0,0 +1,97 @@
""" walk histogram
"""
import sys
import re
import datetime
mol = re.compile("\S+\s(\S+?)\|.{5}(.{6}).\|(.*)\|(.*)")
def main(argv = None):
if argv == None:
argv = sys.argv
ifn = "e:/livefeed/20070829/GDAXI.csv"
ofn = "e:/eclipse/workspace/filter/var/GDAXI_histogram.csv"
tick_list = [ ]
histogram = { }
print "Converting [%s] to [%s]" % (ifn, ofn)
try:
ifh = open(ifn, "r")
ofh = open(ofn, "w")
except IOError:
print "open [%s] failed" % ifn
return 2
try:
for line in ifh:
tick_list.append(parseCsv(line))
for i in xrange(1, len(tick_list)):
diff = tick_list[i].last - tick_list[i-1].last
key = int( diff * 100 )
if key not in histogram:
histogram[key] = 1
else:
histogram[key] += 1
# for key in sorted(histogram.keys()):
for i in xrange(-1000, 1000):
if i in histogram:
print >> ofh, float(i)/100, ",", histogram[i]
else:
print >> ofh, float(i)/100, ",0"
finally:
ifh.close()
ofh.close()
print "Done."
time_pattern = re.compile("(..):(..):(..).(\d+)")
def parseCsv(line):
flds = line.split(',')
mot = re.match(time_pattern, flds[0])
(hh, mm, ss, ms) = mot.group(1, 2, 3, 4)
time = datetime.time(int(hh), int(mm), int(ss), int(ms)*1000)
# pid = flds[1]
bid = flds[2]
ask = flds[3]
last = flds[4]
return Tick(time, float(bid), float(ask), float(last))
class Tick:
""" VDO helper class """
def __init__(self, ti, bid, ask, last):
self.time = ti
self.bid = bid
self.ask = ask
self.last= last
def __cmp__(self, other):
return cmp(self.time, other.time)
class Roi:
""" VDO helper class """
def __init__(self, buy_time, sell_time, pnl):
self.buy_time = buy_time
self.sell_time = sell_time
self.pnl = pnl
def pnl_per_minute(self):
dt = time_in_minutes(self.sell_time) - time_in_minutes(self.buy_time)
try:
ppm = self.pnl / dt
except ZeroDivisionError:
return self.pnl
return ppm
def __cmp__(self, other):
return cmp(self.pnl_per_minute(), other.pnl_per_minute())
def __repr__(self):
return "%s,%s,%.2f,%.2f" % (self.buy_time, self.sell_time,
self.pnl, self.pnl_per_minute())
def time_in_minutes(ti):
return ti.hour * 60 + ti.minute + float(ti.second) / 60
if __name__ == '__main__':
sys.exit(main(sys.argv))

35
src/pricefeed.py Normal file
View File

@@ -0,0 +1,35 @@
""" pricefeed file filter
*.log: "20070905 09:04:56.841|DE000DB0M091|4.430|4.440"
*.csv: "09:04:56.841,DB0M09,4.430,4.440"
"""
import sys
import re
mol = re.compile("\S+\s(\S+?)\|.{5}(.{6}).\|(.*)\|(.*)")
def main(argv = None):
if argv == None:
argv = sys.argv
if (len(argv) != 2):
print "Usage: filter.py <filename.log>"
return 2
ifn = argv[1]
ofn = "".join((ifn.split(".")[0], ".csv"))
print "Converting [%s] to [%s]" % (ifn, ofn)
try:
ifh = open(ifn, "r")
ofh = open(ofn, "w")
except IOError:
print "open [%s] failed" % ifn
return 2
try:
for line in ifh:
flds = mol.match(line)
print >>ofh, ",".join(flds.groups())
finally:
ifh.close()
ofh.close()
if __name__ == '__main__':
sys.exit(main(sys.argv))

94
src/roimatrix.py Normal file
View File

@@ -0,0 +1,94 @@
""" roi matrix
"""
import sys
import re
import datetime
mol = re.compile("\S+\s(\S+?)\|.{5}(.{6}).\|(.*)\|(.*)")
def main(argv = None):
if argv == None:
argv = sys.argv
ifn = "e:/livefeed/20070829/GDAXI.csv"
ofn = "e:/eclipse/workspace/filter/var/GDAXI_roi.csv"
tick_list = [ ]
roi_list = [ ]
print "Converting [%s] to [%s]" % (ifn, ofn)
try:
ifh = open(ifn, "r")
ofh = open(ofn, "w")
except IOError:
print "open [%s] failed" % ifn
return 2
try:
for line in ifh:
tick_list.append(parseCsv(line))
for (i, buy_tick) in enumerate(tick_list[0::300]):
print buy_tick.time
for sell_tick in tick_list[0::300]:
if (buy_tick > sell_tick):
continue
pnl = ( sell_tick.last - buy_tick.last ) * 25.0 - 11.80
# print buy_tick.last, sell_tick.last, pnl
roi_list.append(Roi(buy_tick.time, sell_tick.time, pnl))
for roi in roi_list:
print >> ofh, str(roi)
finally:
ifh.close()
ofh.close()
print "Done."
time_pattern = re.compile("(..):(..):(..).(\d+)")
def parseCsv(line):
flds = line.split(',')
mot = re.match(time_pattern, flds[0])
(hh, mm, ss, ms) = mot.group(1, 2, 3, 4)
time = datetime.time(int(hh), int(mm), int(ss), int(ms)*1000)
# pid = flds[1]
bid = flds[2]
ask = flds[3]
last = flds[4]
return Tick(time, float(bid), float(ask), float(last))
class Tick:
""" VDO helper class """
def __init__(self, ti, bid, ask, last):
self.time = ti
self.bid = bid
self.ask = ask
self.last= last
def __cmp__(self, other):
return cmp(self.time, other.time)
class Roi:
""" VDO helper class """
def __init__(self, buy_time, sell_time, pnl):
self.buy_time = buy_time
self.sell_time = sell_time
self.pnl = pnl
def pnl_per_minute(self):
dt = time_in_minutes(self.sell_time) - time_in_minutes(self.buy_time)
try:
ppm = self.pnl / dt
except ZeroDivisionError:
return self.pnl
return ppm
def __cmp__(self, other):
return cmp(self.pnl_per_minute(), other.pnl_per_minute())
def __repr__(self):
return "%s,%s,%.2f,%.2f" % (self.buy_time, self.sell_time,
self.pnl, self.pnl_per_minute())
def time_in_minutes(ti):
return ti.hour * 60 + ti.minute + float(ti.second) / 60
if __name__ == '__main__':
sys.exit(main(sys.argv))

52
src/wget_batch.py Normal file
View File

@@ -0,0 +1,52 @@
""" broker quote request recorder engine """
import logging
import getopt
import sys
import datetime
mylog = logging.getLogger()
class Usage(Exception):
def __init__(self, message):
Exception.__init__(message)
class Error(Exception):
def __init__(self, message):
Exception.__init__(message)
def main(argv = None):
if argv == None:
argv = sys.argv
mylog.info("starting [%s]" % (argv[0],))
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
print "opts: ", opts, "args:", args
except getopt.error, msg:
raise Usage(msg)
# set up stderr logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s',
datefmt='%H:%M:%S')
# main code starts here
ofh = open("e:/install/asstr_get", "w")
for i in xrange(56546,57096):
# print >> ofh, "wget http://www.literotica.com/stories/showstory.php?id=%i" % i
print >> ofh, "wget http://www.asstr.org/files/Collections/Alt.Sex.Stories.Moderated/Year2007/%i" % i
ofh.close()
except Error, err:
mylog.error(err.message)
return 1
except Usage, err:
mylog.error(err.message)
mylog.error("for help use --help")
return 2
if __name__ == '__main__':
sys.exit(main())