unageanu-jiji 1.1.4 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (233) hide show
  1. data/ChangeLog +24 -1
  2. data/README +0 -0
  3. data/base/shared_lib/moving_average.rb +34 -33
  4. data/base/shared_lib/system/cross.rb +76 -0
  5. data/base/shared_lib/system/position_manager.rb +160 -0
  6. data/base/shared_lib/system/signal.rb +347 -0
  7. data/html/css/datatable.css +4 -4
  8. data/html/css/default.css +57 -5
  9. data/html/css/treeview.css +205 -0
  10. data/html/img/bin_closed.png +0 -0
  11. data/html/img/bin_empty.png +0 -0
  12. data/html/img/button_add_small.gif +0 -0
  13. data/html/img/button_add_small_gray.gif +0 -0
  14. data/html/img/button_add_small_over.gif +0 -0
  15. data/html/img/button_mkcol.gif +0 -0
  16. data/html/img/button_mkcol_gray.gif +0 -0
  17. data/html/img/button_mkcol_over.gif +0 -0
  18. data/html/img/button_remove_small.gif +0 -0
  19. data/html/img/button_remove_small_gray.gif +0 -0
  20. data/html/img/button_remove_small_over.gif +0 -0
  21. data/html/img/button_rename.gif +0 -0
  22. data/html/img/button_rename_gray.gif +0 -0
  23. data/html/img/button_rename_over.gif +0 -0
  24. data/html/img/control_play.png +0 -0
  25. data/html/img/control_play_blue.png +0 -0
  26. data/html/img/folder.png +0 -0
  27. data/html/img/folder_brick.png +0 -0
  28. data/html/img/folder_user.png +0 -0
  29. data/html/{js/codepress/images → img}/line-numbers.png +0 -0
  30. data/html/img/page_white_ruby.png +0 -0
  31. data/html/img/sidebar_agent_edit.png +0 -0
  32. data/html/img/sidebar_agent_edit_over.png +0 -0
  33. data/html/img/sidebar_agent_edit_s.png +0 -0
  34. data/html/img/yui/treeview-sprite.gif +0 -0
  35. data/html/index.html +34 -18
  36. data/html/js/agent-editor/agent-editor-page.js +324 -0
  37. data/html/js/agent-editor/agent-editor.js +363 -0
  38. data/html/js/agent-editor/agent-list-tree.js +251 -0
  39. data/html/js/agent-selector.js +23 -28
  40. data/html/js/app.js +63 -91
  41. data/html/js/bt-create-page.js +25 -19
  42. data/html/js/container-min.js +1 -1
  43. data/html/js/container.js +944 -0
  44. data/html/js/edit_area/autocompletion.js +11 -13
  45. data/html/js/edit_area/edit_area.css +79 -40
  46. data/html/js/edit_area/edit_area.js +255 -226
  47. data/html/js/edit_area/edit_area_compressor.php +4 -4
  48. data/html/js/edit_area/edit_area_full.gz +0 -0
  49. data/html/js/edit_area/edit_area_full.js +31 -31
  50. data/html/js/edit_area/edit_area_full_with_plugins.gz +0 -0
  51. data/html/js/edit_area/edit_area_full_with_plugins.js +31 -31
  52. data/html/js/edit_area/edit_area_functions.js +448 -341
  53. data/html/js/edit_area/edit_area_loader.js +409 -397
  54. data/html/js/edit_area/elements_functions.js +120 -123
  55. data/html/js/edit_area/highlight.js +305 -197
  56. data/html/js/edit_area/images/goto.png +0 -0
  57. data/html/js/edit_area/images/help.png +0 -0
  58. data/html/js/edit_area/images/redo.png +0 -0
  59. data/html/js/edit_area/images/save.png +0 -0
  60. data/html/js/edit_area/images/search.png +0 -0
  61. data/html/js/edit_area/images/undo.png +0 -0
  62. data/html/js/edit_area/images/word_wrap.gif +0 -0
  63. data/html/js/edit_area/keyboard.js +5 -5
  64. data/html/js/edit_area/langs/bg.js +73 -0
  65. data/html/js/edit_area/langs/cs.js +2 -0
  66. data/html/js/edit_area/langs/de.js +2 -0
  67. data/html/js/edit_area/langs/dk.js +2 -0
  68. data/html/js/edit_area/langs/en.js +2 -0
  69. data/html/js/edit_area/langs/eo.js +2 -0
  70. data/html/js/edit_area/langs/es.js +2 -0
  71. data/html/js/edit_area/langs/fi.js +67 -0
  72. data/html/js/edit_area/langs/fr.js +2 -0
  73. data/html/js/edit_area/langs/hr.js +2 -0
  74. data/html/js/edit_area/langs/it.js +2 -0
  75. data/html/js/edit_area/langs/ja.js +2 -0
  76. data/html/js/edit_area/langs/mk.js +2 -0
  77. data/html/js/edit_area/langs/nl.js +2 -0
  78. data/html/js/edit_area/langs/pl.js +2 -0
  79. data/html/js/edit_area/langs/pt.js +2 -0
  80. data/html/js/edit_area/langs/ru.js +2 -0
  81. data/html/js/edit_area/langs/sk.js +2 -0
  82. data/html/js/edit_area/langs/zh.js +67 -0
  83. data/html/js/edit_area/manage_area.js +362 -205
  84. data/html/js/edit_area/plugins/charmap/langs/bg.js +12 -0
  85. data/html/js/edit_area/plugins/charmap/langs/zh.js +6 -0
  86. data/html/js/edit_area/plugins/test/langs/bg.js +10 -0
  87. data/html/js/edit_area/plugins/test/langs/zh.js +4 -0
  88. data/html/js/edit_area/reg_syntax/java.js +56 -0
  89. data/html/js/edit_area/reg_syntax/ruby.js +9 -9
  90. data/html/js/edit_area/reg_syntax.js +15 -13
  91. data/html/js/edit_area/regexp.js +36 -32
  92. data/html/js/edit_area/resize_area.js +43 -47
  93. data/html/js/edit_area/search_replace.js +29 -29
  94. data/html/js/edit_area/template.html +6 -4
  95. data/html/js/json-broker-client.js +23 -17
  96. data/html/js/result-page.js +107 -57
  97. data/html/js/rt-setting-page.js +38 -15
  98. data/html/js/sidebar.js +41 -27
  99. data/html/js/templates.js +167 -32
  100. data/html/js/utils.js +143 -7
  101. data/html/js/yui/treeview.js +3671 -0
  102. data/html/swf/chart.swf +0 -0
  103. data/html/test/agent_editor_spec.js +815 -0
  104. data/html/test/index.html +40 -0
  105. data/html/test/jsspec/JSSpec.css +224 -0
  106. data/html/test/jsspec/JSSpec.js +1549 -0
  107. data/html/test/jsspec/diff_match_patch.js +1 -0
  108. data/html/test/utils_spec.js +111 -0
  109. data/lib/jiji/agent/agent.rb +69 -12
  110. data/lib/jiji/agent/agent_manager.rb +18 -12
  111. data/lib/jiji/agent/agent_registry.rb +35 -121
  112. data/lib/jiji/collector.rb +16 -6
  113. data/lib/jiji/command.rb +46 -5
  114. data/lib/jiji/dao/file_system_dao.rb +158 -0
  115. data/lib/jiji/dao/timed_data_dao.rb +2 -0
  116. data/lib/jiji/dao/trade_result_dao.rb +1 -1
  117. data/lib/jiji/error.rb +24 -8
  118. data/lib/jiji/migration/migrator1_2_0.rb +67 -0
  119. data/lib/jiji/models.rb +82 -24
  120. data/lib/jiji/operator.rb +55 -51
  121. data/lib/jiji/output.rb +85 -29
  122. data/lib/jiji/output_manager.rb +84 -0
  123. data/lib/jiji/plugin/embedded/single_click_client.rb +2 -2
  124. data/lib/jiji/plugin/securities_plugin.rb +0 -1
  125. data/lib/jiji/process.rb +229 -208
  126. data/lib/jiji/process_manager.rb +190 -96
  127. data/lib/jiji/registry.rb +87 -19
  128. data/lib/jiji/server.rb +1 -0
  129. data/lib/jiji/service/agent_service.rb +147 -48
  130. data/lib/jiji/service/output_service.rb +37 -17
  131. data/lib/jiji/service/process_service.rb +3 -5
  132. data/lib/jiji/service/trade_result_service.rb +4 -5
  133. data/lib/jiji/util/file_lock.rb +4 -4
  134. data/lib/jiji/util/include_proxy.rb +17 -0
  135. data/lib/jiji/util/json_broker.rb +6 -4
  136. data/lib/jiji/util/util.rb +1 -1
  137. data/swf/chart/fx/chart/Chart.as +7 -0
  138. data/swf/chart/fx/chart/ui/graph/GraphManager.as +15 -2
  139. data/test/ProcessTest/agents/foo.rb +10 -0
  140. data/test/ProcessTest/conf/configuration.yaml +3 -0
  141. data/test/agent/agent_tests.rb +10 -0
  142. data/test/agent/test_AgentManager.rb +28 -12
  143. data/test/agent/test_AgentRegistry.rb +194 -99
  144. data/test/agent/test_PeriodicallyAgent.rb +1 -2
  145. data/test/agent/test_Permitter.rb +1 -2
  146. data/test/all_tests.rb +7 -19
  147. data/test/dao/dao_tests.rb +9 -0
  148. data/test/dao/test_FileSystemDao.rb +431 -0
  149. data/test/dao/test_RateDao.rb +5 -7
  150. data/test/dao/test_TradeResultDao.rb +1 -2
  151. data/test/migration/migration_tests.rb +10 -0
  152. data/test/migration/migrator1_2_0test_data/basic/out/M2NlOTA2ODEtZDdlNi00NWU1LWIwNDQtMjBmODY2ZGNkNzBj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  153. data/test/migration/migrator1_2_0test_data/basic/out/MDVhYzcxMjYtMGFlMS00Mzk0LWEyNmUtYjVjZjgwNDA0ZmE2/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  154. data/test/migration/migrator1_2_0test_data/basic/out/MzA1YTk0NDgtNzhjNi00NDk3LTk2NTktYzE1ZjBhNzdiYjNj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  155. data/test/migration/migrator1_2_0test_data/basic/out/YjRkOTI1MzEtZTM4MS00YjQwLTg1ZTQtMWFmZDRlNDUwMzBm/56e75YuV5bmz5Z2H57ea/meta.yaml +9 -0
  156. data/test/migration/migrator1_2_0test_data/basic/props.yaml +85 -0
  157. data/test/migration/migrator1_2_0test_data/illegal_props/out/M2NlOTA2ODEtZDdlNi00NWU1LWIwNDQtMjBmODY2ZGNkNzBj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  158. data/test/migration/migrator1_2_0test_data/illegal_props/out/MDVhYzcxMjYtMGFlMS00Mzk0LWEyNmUtYjVjZjgwNDA0ZmE2/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  159. data/test/migration/migrator1_2_0test_data/illegal_props/out/MzA1YTk0NDgtNzhjNi00NDk3LTk2NTktYzE1ZjBhNzdiYjNj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  160. data/test/migration/migrator1_2_0test_data/illegal_props/out/YjRkOTI1MzEtZTM4MS00YjQwLTg1ZTQtMWFmZDRlNDUwMzBm/56e75YuV5bmz5Z2H57ea/meta.yaml +9 -0
  161. data/test/migration/migrator1_2_0test_data/illegal_props/props.yaml +1 -0
  162. data/test/migration/migrator1_2_0test_data/no_outs/props.yaml +85 -0
  163. data/test/migration/migrator1_2_0test_data/no_props/out/M2NlOTA2ODEtZDdlNi00NWU1LWIwNDQtMjBmODY2ZGNkNzBj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  164. data/test/migration/migrator1_2_0test_data/no_props/out/MDVhYzcxMjYtMGFlMS00Mzk0LWEyNmUtYjVjZjgwNDA0ZmE2/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  165. data/test/migration/migrator1_2_0test_data/no_props/out/MzA1YTk0NDgtNzhjNi00NDk3LTk2NTktYzE1ZjBhNzdiYjNj/56e75YuV5bmz5Z2H57ea/meta.yaml +8 -0
  166. data/test/migration/migrator1_2_0test_data/no_props/out/YjRkOTI1MzEtZTM4MS00YjQwLTg1ZTQtMWFmZDRlNDUwMzBm/56e75YuV5bmz5Z2H57ea/meta.yaml +9 -0
  167. data/test/migration/test_Migrator.rb +1 -1
  168. data/test/migration/test_Migrator1_0_3.rb +1 -1
  169. data/test/migration/test_Migrator1_1_0.rb +1 -1
  170. data/test/migration/test_Migrator1_2_0.rb +94 -0
  171. data/test/plugin/embedded/test_SingleClickClient.rb +1 -2
  172. data/test/plugin/plugin_tests.rb +8 -0
  173. data/test/plugin/test_Loader.rb +1 -1
  174. data/test/shared/rate.csv +144 -0
  175. data/test/shared/shared_tests.rb +9 -0
  176. data/test/shared/test_Cross.rb +144 -0
  177. data/test/shared/test_PositionManager.rb +285 -0
  178. data/test/shared/test_Signal.rb +65 -0
  179. data/test/test_Output.rb +28 -21
  180. data/test/test_OutputManager.rb +162 -0
  181. data/test/test_Output_registry.rb +6 -17
  182. data/test/test_Process.rb +434 -222
  183. data/test/test_ProcessManager.rb +458 -101
  184. data/test/test_utils.rb +71 -8
  185. data/test/util/test_BlockToSession.rb +1 -2
  186. data/test/util/test_CSV.rb +1 -2
  187. data/test/util/test_SynchronizeInterceptor.rb +1 -2
  188. data/test/util/util_tests.rb +9 -0
  189. metadata +127 -47
  190. data/html/js/agent-editor-page.js +0 -440
  191. data/html/js/codepress/codepress.css +0 -21
  192. data/html/js/codepress/codepress.html +0 -35
  193. data/html/js/codepress/codepress.js +0 -138
  194. data/html/js/codepress/engines/gecko.js +0 -293
  195. data/html/js/codepress/engines/khtml.js +0 -0
  196. data/html/js/codepress/engines/msie.js +0 -304
  197. data/html/js/codepress/engines/older.js +0 -0
  198. data/html/js/codepress/engines/opera.js +0 -260
  199. data/html/js/codepress/images/line-numbers.gif +0 -0
  200. data/html/js/codepress/index.html +0 -443
  201. data/html/js/codepress/languages/asp.css +0 -71
  202. data/html/js/codepress/languages/asp.js +0 -117
  203. data/html/js/codepress/languages/autoit.css +0 -13
  204. data/html/js/codepress/languages/autoit.js +0 -32
  205. data/html/js/codepress/languages/csharp.css +0 -9
  206. data/html/js/codepress/languages/csharp.js +0 -25
  207. data/html/js/codepress/languages/css.css +0 -10
  208. data/html/js/codepress/languages/css.js +0 -23
  209. data/html/js/codepress/languages/generic.css +0 -9
  210. data/html/js/codepress/languages/generic.js +0 -25
  211. data/html/js/codepress/languages/html.css +0 -13
  212. data/html/js/codepress/languages/html.js +0 -59
  213. data/html/js/codepress/languages/java.css +0 -7
  214. data/html/js/codepress/languages/java.js +0 -24
  215. data/html/js/codepress/languages/javascript.css +0 -8
  216. data/html/js/codepress/languages/javascript.js +0 -30
  217. data/html/js/codepress/languages/perl.css +0 -11
  218. data/html/js/codepress/languages/perl.js +0 -27
  219. data/html/js/codepress/languages/php.css +0 -12
  220. data/html/js/codepress/languages/php.js +0 -61
  221. data/html/js/codepress/languages/ruby.css +0 -10
  222. data/html/js/codepress/languages/ruby.js +0 -26
  223. data/html/js/codepress/languages/sql.css +0 -10
  224. data/html/js/codepress/languages/sql.js +0 -30
  225. data/html/js/codepress/languages/text.css +0 -5
  226. data/html/js/codepress/languages/text.js +0 -9
  227. data/html/js/codepress/languages/vbscript.css +0 -71
  228. data/html/js/codepress/languages/vbscript.js +0 -117
  229. data/html/js/codepress/languages/xsl.css +0 -15
  230. data/html/js/codepress/languages/xsl.js +0 -103
  231. data/html/js/codepress/license.txt +0 -458
  232. data/html/js/edit_area/images/Thumbs.db +0 -0
  233. data/test/plugin/test_gem/a/lib/jiji_plugin_test.rb +0 -6
data/ChangeLog CHANGED
@@ -1,7 +1,30 @@
1
1
 
2
+ 2009-8-15 1.2.0
3
+ * エージェントエディタを一新
4
+ - 複数のエージェントや共有ライブラリをタブで同時に編集できるようになりました。
5
+ - エージェントや共有ライブラリをディレクトリで分類できるようになりました。
6
+
7
+ * 標準ライブラリの追加
8
+ 標準添付の共有ライブラリとして、以下を追加。
9
+ - 移動平均などの各種シグナル算出クラス
10
+ - ロスカットやトレーリングストップを容易に実現するPositionManager
11
+ - クロスアップ、クロスダウンを判定するためのユーティリティ
12
+
13
+ * バックテストの再実行機能を追加
14
+ - バックテストを1クリックで再実行できるようになりました。
15
+
16
+ * グラフ出力の不具合修正
17
+ - エージェントを削除するとそのグラフも表示できなくなる問題を改修しました。
18
+ - この変更でリアルトレードでは古いグラフが蓄積されていくようになったため、
19
+ 不要なグラフを破棄する機能も追加しました。
20
+
21
+ 2009-8-8 1.1.4
22
+ * クリック証券デモ取引Webサービスの提供終了にあわせて、デモ取引接続プラグインを
23
+ 無効化
24
+
2
25
  2009-7-5 1.1.3
3
26
  * クリック証券のデモ取引に接続する場合に、設定でプロキシを空のまま確定すると
4
-  接続エラーになる不具合を改修。
27
+ 接続エラーになる不具合を改修。
5
28
 
6
29
  2009-6-29 1.1.2
7
30
  * クリック証券プラグインを標準添付
data/README CHANGED
File without changes
@@ -1,34 +1,35 @@
1
- # 一定期間の移動平均を得る
2
- class MovingAverage
3
- def initialize( range=25 )
4
- @rates = [] # レートを記録するバッファ
5
- @range = range
6
- end
7
-
8
- def next_rate( rate )
9
- # バッファのデータを更新
10
- @rates.push rate
11
- @rates.shift if @rates.length > @range
12
-
13
- # バッファサイズが十分でなければ、nilを返す。
14
- return nil if @rates.length != @range
15
-
16
- # 移動平均を算出
17
- return MovingAverage.get_moving_average(@rates)
18
- end
19
-
20
- # 前の結果(引数で指定した件数だけ記録。)
21
- attr :prev, true
22
-
23
- private
24
- # 移動平均値を計算する。
25
- def self.get_moving_average( rates )
26
- total = 0
27
- rates.each {|s|
28
- total += s.end
29
- total += s.max
30
- total += s.min
31
- }
32
- return total / ( rates.length * 3 )
33
- end
1
+
2
+ # 一定期間の移動平均を得る
3
+ class MovingAverage
4
+ def initialize( range=25 )
5
+ @rates = [] # レートを記録するバッファ
6
+ @range = range
7
+ end
8
+
9
+ def next_rate( rate )
10
+ # バッファのデータを更新
11
+ @rates.push rate
12
+ @rates.shift if @rates.length > @range
13
+
14
+ # バッファサイズが十分でなければ、nilを返す。
15
+ return nil if @rates.length != @range
16
+
17
+ # 移動平均を算出
18
+ return MovingAverage.get_moving_average(@rates)
19
+ end
20
+
21
+ # 前の結果(引数で指定した件数だけ記録。)
22
+ attr :prev, true
23
+
24
+ private
25
+ # 移動平均値を計算する。
26
+ def self.get_moving_average( rates )
27
+ total = 0
28
+ rates.each {|s|
29
+ total += s.end
30
+ total += s.max
31
+ total += s.min
32
+ }
33
+ return total / ( rates.length * 3 )
34
+ end
34
35
  end
@@ -0,0 +1,76 @@
1
+
2
+ #===交差状態を判定するユーティリティ
3
+ #先行指標と遅行指標を受け取って、クロスアップ/クロスダウンを判定するユーティリティです。
4
+ #
5
+ # require 'cross'
6
+ #
7
+ # cross = Cross.new
8
+ #
9
+ # # 先行指標、遅行指標を受け取って状態を返す。
10
+ # # :cross .. クロスアップ、クロスダウン状態かどうかを返す。
11
+ # # - クロスアップ(:up)
12
+ # # - クロスダウン(:down)
13
+ # # - どちらでもない(:none)
14
+ # # :trend .. 現在の指標が上向きか下向きかを返す。
15
+ # # 「先行指標 <=> 遅行指標」した値。
16
+ # # trend >= 1なら上向き、trned <= -1なら下向き
17
+ # p cross.next_data( 100, 90 ) # {:trend=>1, :cross=>:none}
18
+ # p cross.next_data( 110, 100 ) # {:trend=>1, :cross=>:none}
19
+ # p cross.next_data( 100, 100 ) # {:trend=>0, :cross=>:none}
20
+ # p cross.next_data( 90, 100 ) # {:trend=>-1, :cross=>:down}
21
+ # p cross.next_data( 80, 90 ) # {:trend=>-1, :cross=>:none}
22
+ # p cross.next_data( 90, 90 ) # {:trend=>0, :cross=>:none}
23
+ # p cross.next_data( 100, 100 ) # {:trend=>0, :cross=>:none}
24
+ # p cross.next_data( 110, 100 ) # {:trend=>1, :cross=>:up}
25
+ #
26
+ class Cross
27
+
28
+ #コンストラクタ
29
+ def initialize
30
+ @cross_prev = nil
31
+ @cross = :none
32
+ @trend = 0
33
+ end
34
+
35
+ #===次の値を渡し状態を更新します。
36
+ #fast:: 先行指標
37
+ #lazy:: 遅行指標
38
+ def next_data( fast, lazy )
39
+ return unless fast && lazy
40
+ # 交差状態を算出
41
+ @trend = fast <=> lazy
42
+ if @cross_prev && @trend != @cross_prev && @trend != 0
43
+ @cross = @trend > @cross_prev ? :up : :down
44
+ else
45
+ @cross = :none
46
+ end
47
+ @cross_prev = @trend
48
+ return {:cross=>@cross,:trend=>@trend}
49
+ end
50
+
51
+ #===クロスアップ状態かどうか判定します。
52
+ #戻り値:: 「先行指標 < 遅行指標」 から 「先行指標 > 遅行指標」 になったらtrue
53
+ def cross_up?
54
+ @cross == :up
55
+ end
56
+ #===クロスダウン状態かどうか判定します。
57
+ #戻り値:: 「先行指標 > 遅行指標」 から 「先行指標 < 遅行指標」 になったらtrue
58
+ def cross_down?
59
+ @cross == :down
60
+ end
61
+ #===上昇トレンド中かどうか判定します。
62
+ #戻り値:: 「先行指標 > 遅行指標」 ならtrue
63
+ def up?
64
+ @trend > 0
65
+ end
66
+ #===下降トレンド中かどうか判定します。
67
+ #戻り値:: 「先行指標 < 遅行指標」 ならtrue
68
+ def down?
69
+ @trend < 0
70
+ end
71
+
72
+ #交差状態( :up, :down, :none )
73
+ attr_reader :cross
74
+ #トレンド ( 直近の falst <=> lazy 値。)
75
+ attr_reader :trend
76
+ end
@@ -0,0 +1,160 @@
1
+
2
+ #===ポジションマネージャ
3
+ #以下の機能を提供するユーティリティクラスです。
4
+ #- 条件にマッチするポジションを探す。
5
+ #- すべてのor条件にマッチするポジションを決済する。
6
+ #- 指定したポジションを損切りorトレーリングストップで決済する。
7
+ class PositionManager
8
+ include Enumerable
9
+
10
+ #====コンストラクタ
11
+ #operator:: オペレータ
12
+ def initialize( operator )
13
+ raise "illegal argument." unless operator
14
+ @operator = operator
15
+ @marked = {}
16
+ end
17
+
18
+ #====ポジションを列挙します。
19
+ def each( &block )
20
+ @operator.positions.each_pair {|k,v|
21
+ yield v
22
+ }
23
+ end
24
+
25
+ #====条件にマッチするポジションを決済します。
26
+ #&block:: 決済するポジションを判定するブロック。JIJI::Positionが引数として渡され、trueが返された場合決済されます。
27
+ def commit_by
28
+ each {|p|
29
+ @operator.commit( p ) if yield p
30
+ }
31
+ end
32
+
33
+ #====すべてのポジションを決済します。
34
+ def commit_all
35
+ commit_by{|p| true }
36
+ end
37
+
38
+ #====現在保有しているポジションの損益合計を取得します。
39
+ #※決済済みポジションの損益は含まれません。
40
+ #戻り値:: 現在保有しているポジションの損益合計
41
+ def total_profit_or_loss
42
+ inject(0.0) {|t, p|
43
+ t += p.profit_or_loss
44
+ }
45
+ end
46
+
47
+ #====ポジションに損切りロジックを登録します。
48
+ #損切りロジックが登録されたポジションはcheckが実行される度に損益がチェックされ、
49
+ #PositionManager::StopStrategy.close?がtrueになれば決済されます。
50
+ #1つのポジションに対して複数のロジックを設定可能。いずれかのロジックがtrueを返せば損切りされます。
51
+ #position_id:: ポジションID
52
+ #stop_strategy:: 損切りルール(PositionManager::StopStrategy)
53
+ def register( position_id, stop_strategy )
54
+ @marked[position_id] ||= []
55
+ @marked[position_id] << stop_strategy
56
+ end
57
+
58
+ #====ポジションをロスカットの対象としてマークします。
59
+ #マークされたポジションはcheckが実行される度に損益がチェックされ、
60
+ #損失がdissipationで設定した値以下になっていれば決済されます。
61
+ #
62
+ #position_id:: ポジションID
63
+ #dissipation:: 許容しうる損失
64
+ def register_loss_cut( position_id, dissipation )
65
+ register(position_id,LossCut.new( dissipation ))
66
+ end
67
+
68
+ #====ポジションをトレーリングストップの対象としてマークします。
69
+ #マークされたポジションはcheckが実行される度に損益がチェックされ、
70
+ #「今までの最高損益-現在の損益」がdissipationで設定した値以下になっていれば決済されます。
71
+ #
72
+ #position_id:: ポジションID
73
+ #dissipation:: 許容しうる損失
74
+ def register_trailing_stop( position_id, dissipation )
75
+ register(position_id,TrailingStop.new( dissipation ))
76
+ end
77
+
78
+ #====ポジションに損切りロジックが登録されているかどうか評価します。
79
+ #position_id:: ポジションID
80
+ #return:: 損切りの対象であればtrue
81
+ def registered?( position_id )
82
+ @marked.key?(position_id)
83
+ end
84
+
85
+ #====ポジションに登録されている損切りロジックの一覧を取得します。
86
+ #position_id:: ポジションID
87
+ #return:: ポジションに登録されている損切りロジックの配列
88
+ def get_registered_strategy( position_id )
89
+ @marked[position_id] || []
90
+ end
91
+
92
+ #====ポジションに登録された損切りロジックを解除します。
93
+ #position_id:: ポジションID
94
+ #strategy:: 削除する損切りロジック
95
+ def unregister(position_id, strategy)
96
+ list = get_registered_strategy(position_id)
97
+ list.delete(strategy)
98
+ end
99
+
100
+ #====ポジションに登録された損切りロジックを全て解除します。
101
+ #position_id:: ポジションID
102
+ def unregister_all(position_id)
103
+ @marked.delete( position_id )
104
+ end
105
+
106
+
107
+ #====監視対象のポジションが閾値を越えていないかチェックし、必要があれば決済します。
108
+ #定期的に実行してください。
109
+ #戻り値:: 決済したポジションの配列
110
+ def check
111
+ commited = []
112
+ @marked.each_pair {|k,v|
113
+ p = @operator.positions[k]
114
+ if !p || p.state != JIJI::Position::STATE_START
115
+ @marked.delete p.position_id
116
+ else
117
+ v.each {|strategy|
118
+ next unless strategy.close?(p)
119
+ @operator.commit( p )
120
+ commited << p
121
+ unregister_all( p.position_id )
122
+ break
123
+ }
124
+ end
125
+ }
126
+ commited
127
+ end
128
+
129
+ #===手じまい戦略
130
+ module StopStrategy
131
+ #====決済すべきか評価する。
132
+ #position:: ポジション(JIJI::Position)
133
+ def close?(position)
134
+ return false
135
+ end
136
+ end
137
+ #===トレーリングストップ
138
+ class TrailingStop
139
+ include StopStrategy
140
+ def initialize( dissipation )
141
+ @dissipation=dissipation
142
+ end
143
+ def close?(position)
144
+ @max=0 if !@max
145
+ result = (@max - position.profit_or_loss)*-1 <= @dissipation
146
+ @max = [position.profit_or_loss, @max].max
147
+ return result
148
+ end
149
+ end
150
+ #===ロスカット
151
+ class LossCut
152
+ include StopStrategy
153
+ def initialize( dissipation )
154
+ @dissipation=dissipation
155
+ end
156
+ def close?(position)
157
+ position.profit_or_loss <= @dissipation
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,347 @@
1
+
2
+ module Signal
3
+
4
+ #===一定期間のレートデータを元に値を算出するシグナルの基底クラス
5
+ class RangeSignal
6
+ include Signal
7
+ #====コンストラクタ
8
+ #range:: 集計期間
9
+ def initialize( range=25 )
10
+ @datas = [] # レートを記録するバッファ
11
+ @range = range
12
+ end
13
+ #====次のデータを受け取って指標を返します。
14
+ #data:: 次のデータ
15
+ #戻り値:: 指標。十分なデータが蓄積されていない場合nil
16
+ def next_data( data )
17
+ # バッファのデータを更新
18
+ @datas.push data
19
+ @datas.shift if @datas.length > @range
20
+
21
+ # バッファサイズが十分でなければ、nilを返す。
22
+ return nil if @datas.length != @range
23
+
24
+ # 算出
25
+ return calculate(@datas)
26
+ end
27
+ #
28
+ def calculate(datas); end #:nodoc:
29
+ #集計期間
30
+ attr_reader :range
31
+ end
32
+
33
+ #===移動平均
34
+ class MovingAverage < RangeSignal
35
+ def calculate(datas) #:nodoc:
36
+ ma( datas )
37
+ end
38
+ end
39
+
40
+ #===加重移動平均
41
+ class WeightedMovingAverage < RangeSignal
42
+ def calculate(datas) #:nodoc:
43
+ wma( datas )
44
+ end
45
+ end
46
+
47
+ #===指数移動平均
48
+ class ExponentialMovingAverage < RangeSignal
49
+ #====コンストラクタ
50
+ #range:: 集計期間
51
+ #smoothing_coefficient:: 平滑化係数
52
+ def initialize( range=25, smoothing_coefficient=0.1 )
53
+ super(range)
54
+ @sc = smoothing_coefficient
55
+ end
56
+ def calculate(datas) #:nodoc:
57
+ ema( datas, @sc )
58
+ end
59
+ end
60
+
61
+ #===ボリンジャーバンド
62
+ class BollingerBands < RangeSignal
63
+ #====コンストラクタ
64
+ #range:: 集計期間
65
+ #pivot:: ピボット
66
+ def initialize( range=25, pivot=[0,1,2], &block )
67
+ super(range)
68
+ @pivot = pivot
69
+ @block = block
70
+ end
71
+ def calculate(datas) #:nodoc:
72
+ bollinger_bands( datas, @pivot, &@block )
73
+ end
74
+ end
75
+
76
+ #===傾き
77
+ class Momentum < RangeSignal
78
+ def calculate(datas) #:nodoc:
79
+ momentum( datas )
80
+ end
81
+ end
82
+
83
+ #===傾き(最小二乗法を利用)
84
+ class Vector < RangeSignal
85
+ def calculate(datas)
86
+ vector( datas )
87
+ end
88
+ end
89
+
90
+ #===MACD
91
+ class MACD < RangeSignal
92
+ #====コンストラクタ
93
+ #short_range:: 短期EMAの集計期間
94
+ #long_range:: 長期EMAの集計期間
95
+ #signal_range:: シグナルの集計期間
96
+ #smoothing_coefficient:: 平滑化係数
97
+ def initialize( short_range=12, long_range=26,
98
+ signal_range=9, smoothing_coefficient=0.1 )
99
+ raise "illegal arguments." if short_range > long_range
100
+ super(long_range)
101
+ @short_range = short_range
102
+ @smoothing_coefficient = smoothing_coefficient
103
+ @signal = ExponentialMovingAverage.new(
104
+ signal_range, smoothing_coefficient )
105
+ end
106
+ def next_data( data ) #:nodoc:
107
+ macd = super
108
+ return nil unless macd
109
+ signal = @signal.next_data( macd )
110
+ return nil unless signal
111
+ return { :macd=>macd, :signal=>signal }
112
+ end
113
+ def calculate(datas) #:nodoc:
114
+ macd( datas, @short_range, range, @smoothing_coefficient )
115
+ end
116
+ end
117
+
118
+ #===RSI
119
+ class RSI < RangeSignal
120
+ #====コンストラクタ
121
+ #range:: 集計期間
122
+ def initialize( range=14 )
123
+ super(range)
124
+ end
125
+ def calculate(datas) #:nodoc:
126
+ rsi( datas )
127
+ end
128
+ end
129
+
130
+ #===DMI
131
+ class DMI < RangeSignal
132
+ #====コンストラクタ
133
+ #range:: 集計期間
134
+ def initialize( range=14 )
135
+ super(range)
136
+ @dxs = []
137
+ end
138
+ def calculate(datas) #:nodoc:
139
+ dmi = dmi( datas )
140
+ return nil unless dmi
141
+ @dxs.push dmi[:dx]
142
+ @dxs.shift if @dxs.length > range
143
+ return nil if @dxs.length != range
144
+ dmi[:adx] = ma( @dxs )
145
+ return dmi
146
+ end
147
+ end
148
+
149
+ #===ROC
150
+ class ROC < RangeSignal
151
+ #====コンストラクタ
152
+ #range:: 集計期間
153
+ def initialize( range=14 )
154
+ super(range)
155
+ end
156
+ def calculate(datas) #:nodoc:
157
+ roc( datas )
158
+ end
159
+ end
160
+
161
+ module_function
162
+
163
+ #===移動平均値を計算します。
164
+ #datas:: 値の配列。
165
+ #戻り値:: 移動平均値
166
+ def ma( datas )
167
+ total = datas.inject {|t,s|
168
+ t += s; t
169
+ }
170
+ return total / datas.length
171
+ end
172
+
173
+ #===加重移動平均値を計算します。
174
+ #datas:: 値の配列。
175
+ #戻り値:: 加重移動平均値
176
+ def wma( datas )
177
+ weight = 1
178
+ total = datas.inject(0.0) {|t,s|
179
+ t += s * weight
180
+ weight += 1
181
+ t
182
+ }
183
+ return total / ( datas.length * (datas.length+1) /2 )
184
+ end
185
+
186
+ #===指数移動平均値を計算します。
187
+ #datas:: 値の配列。
188
+ #smoothing_coefficient:: 平滑化係数
189
+ #戻り値:: 加重移動平均値
190
+ def ema( datas, smoothing_coefficient=0.1 )
191
+ datas[1..-1].inject( datas[0] ) {|t,s|
192
+ t + smoothing_coefficient * (s - t)
193
+ }
194
+ end
195
+
196
+ #
197
+ #===ボリンジャーバンドを計算します。
198
+ #
199
+ # +2σ=移動平均+標準偏差×2
200
+ # +σ=移動平均+標準偏差
201
+ # -σ=移動平均-標準偏差
202
+ # -2σ=移動平均-標準偏差×2
203
+ # 標準偏差=√((各値-値の期間中平均値)の2乗を期間分全部加えたもの)/ 期間
204
+ # (√は式全体にかかる)
205
+ #
206
+ #datas:: 値の配列
207
+ #pivot:: 標準偏差の倍数。初期値[0,1,2]
208
+ #block:: 移動平均を算出するロジック。指定がなければ移動平均を使う。
209
+ #戻り値:: ボリンジャーバンドの各値の配列。例) [+2σ, +1σ, TP, -1σ, -2σ]
210
+ #
211
+ def bollinger_bands( datas, pivot=[0,1,2], &block )
212
+ ma = block_given? ? yield( datas ) : ma( datas )
213
+ total = datas.inject(0.0) {|t,s|
214
+ t+= ( s - ma ) ** 2
215
+ t
216
+ }
217
+ sd = Math.sqrt(total / datas.length)
218
+ res = []
219
+ pivot.each { |r|
220
+ res.unshift( ma + sd * r )
221
+ res.push( ma + sd * r * -1 ) if r != 0
222
+ }
223
+ return res
224
+ end
225
+
226
+ #===一定期間の値の傾きを計算します。
227
+ #datas:: 値の配列
228
+ #戻り値:: 傾き。0より大きければ上向き。小さければ下向き。
229
+ def momentum( datas )
230
+ (datas.last - datas.first) / datas.length
231
+ end
232
+
233
+ #===最小二乗法で、一定期間の値の傾きを計算します。
234
+ #datas:: 値の配列
235
+ #戻り値:: 傾き。0より大きければ上向き。小さければ下向き。
236
+ def vector( datas )
237
+ # 最小二乗法を使う。
238
+ total = {:x=>0.0,:y=>0.0,:xx=>0.0,:xy=>0.0,:yy=>0.0}
239
+ datas.each_index {|i|
240
+ total[:x] += i
241
+ total[:y] += datas[i]
242
+ total[:xx] += i*i
243
+ total[:xy] += i*datas[i]
244
+ total[:yy] += datas[i] * datas[i]
245
+ }
246
+ n = datas.length
247
+ d = total[:xy]
248
+ c = total[:y]
249
+ e = total[:x]
250
+ b = total[:xx]
251
+ return (n*d - c*e) / (n*b - e*e)
252
+ end
253
+
254
+ #===MACDを計算します。
255
+ #MACD = 短期(short_range日)の指数移動平均 - 長期(long_range日)の指数移動平均
256
+ #datas:: 値の配列
257
+ #smoothing_coefficient:: 平滑化係数
258
+ #戻り値:: macd値
259
+ def macd( datas, short_range, long_range, smoothing_coefficient )
260
+ ema( datas[ short_range*-1 .. -1], smoothing_coefficient ) \
261
+ - ema( datas[ long_range*-1 .. -1], smoothing_coefficient )
262
+ end
263
+
264
+ #===RSIを計算します。
265
+ #RSI = n日間の値上がり幅合計 / (n日間の値上がり幅合計 + n日間の値下がり幅合計) * 100
266
+ #nとして、14や9を使うのが、一般的。30以下では売られすぎ70以上では買われすぎの水準。
267
+ #
268
+ #datas:: 値の配列
269
+ #戻り値:: RSI値
270
+ def rsi( datas )
271
+ prev = nil
272
+ tmp = datas.inject( [0.0,0.0] ) {|r,i|
273
+ r[ i > prev ? 0 : 1 ] += (i - prev).abs if prev
274
+ prev = i
275
+ r
276
+ }
277
+ (tmp[0] + tmp[1] ) == 0 ? 0.0 : tmp[0] / (tmp[0] + tmp[1]) * 100
278
+ end
279
+
280
+ #===DMIを計算します。
281
+ #
282
+ # 高値更新 ... 前日高値より当日高値が高かった時その差
283
+ # 安値更新 ... 前日安値より当日安値が安かった時その差
284
+ # DM ... 高値更新が安値更新より大きかった時高値更新の値。逆の場合は0
285
+ # DM ... 安値更新が高値更新より大きかった時安値更新の値。逆の場合は0
286
+ # TR ... 次の3つの中で一番大きいもの
287
+ # 当日高値-当日安値
288
+ # 当日高値-前日終値
289
+ # 前日終値-当日安値
290
+ # AV(+DM) ... +DMのn日間移動平均値
291
+ # AV(-DM) ... -DMのn日間移動平均値
292
+ # AV(TR) ... TRのn日間移動平均値
293
+ # +DI ... AV(+DM)/AV(TR)
294
+ # -DI ... AV(-DM)/AV(TR)
295
+ # DX ... (+DIと-DIの差額) / (+DIと-DIの合計)
296
+ # ADX ... DXのn日平均値
297
+ #
298
+ #datas:: 値の配列(4本値を指定すること!)
299
+ #戻り値:: {:pdi=pdi, :mdi=mdi, :dx=dx }
300
+ def dmi( datas )
301
+ prev = nil
302
+ tmp = datas.inject( [[],[],[]] ) {|r,i|
303
+ if prev
304
+ dm = _dmi( i, prev )
305
+ r[0] << dm[0] # TR
306
+ r[1] << dm[1] # +DM
307
+ r[2] << dm[2] # -DM
308
+ end
309
+ prev = i
310
+ r
311
+ }
312
+ atr = ma( tmp[0] )
313
+ pdi = ma( tmp[1] ) / atr * 100
314
+ mdi = ma( tmp[2] ) / atr * 100
315
+ dx = ( pdi-mdi ).abs / ( pdi+mdi ) * 100
316
+ return {:pdi=>pdi, :mdi=>mdi, :dx=>dx }
317
+ end
318
+
319
+ #TR,+DM,-DMを計算します。
320
+ #戻り値:: [ tr, +DM, -DM ]
321
+ def _dmi( rate, rate_prev ) #:nodoc:
322
+ pdm = rate.max > rate_prev.max ? rate.max - rate_prev.max : 0
323
+ mdm = rate.min < rate_prev.min ? rate_prev.min - rate.min : 0
324
+
325
+ if ( pdm > mdm )
326
+ mdm = 0
327
+ elsif ( pdm < mdm )
328
+ pdm = 0
329
+ end
330
+
331
+ a = rate.max - rate.min
332
+ b = rate.max - rate_prev.end
333
+ c = rate_prev.end - rate.min
334
+ tr = [a,b,c].max
335
+
336
+ return [tr, pdm, mdm]
337
+ end
338
+
339
+ #===ROCを計算します。
340
+ #Rate of Change。変化率。正なら上げトレンド、負なら下げトレンド。
341
+ #
342
+ #datas:: 値の配列
343
+ #戻り値:: 値
344
+ def roc( datas )
345
+ (datas.first - datas.last) / datas.last * 100
346
+ end
347
+ end