Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next_tickの間隔について #416

Open
JunyaW opened this issue Nov 26, 2017 · 25 comments
Open

next_tickの間隔について #416

JunyaW opened this issue Nov 26, 2017 · 25 comments

Comments

@JunyaW
Copy link

JunyaW commented Nov 26, 2017

素晴らしいシステムトレードフレームワーク、ありがとうございます。
初心者なのですが質問がございます。

next_tickの行われる間隔を15秒からより長い時間に変更することはできるのでしょうか?

@unageanu
Copy link
Owner

環境変数 TICK_INTERVAL を指定することで変更可能です。
docker-compose.yml に以下の設定を追加して再起動してみてください。

jiji:
  container_name: jiji_jiji
  image: unageanu/jiji:latest
  links:
    - mongodb
  environment:
    USER_SECRET: (略)
    TICK_INTERVAL: 60  # ←間隔を秒で指定
(略)

@JunyaW
Copy link
Author

JunyaW commented Nov 27, 2017

返信ありがとうございます。ど素人なので、具体的に困っていることを尋ねさせてください。

現在、HerokuにJijiをインストールして、defaultのmoving_average_agent.rbを自分用にカスタマイズしようとしています。そのなかで、42行目以降の以下の部分を変更すれば、tickの間隔をコントロールできるのではないかと思い、質問させてもらいました。そもそも方針が間違っているでしょうか?

moving_average_agent.rbの42行目以降


次のレートを受け取る

def next_tick(tick)
# 移動平均を計算
res = @mvs.map { |mv| mv.next_data(tick[:USDJPY].bid) }
return if !res[0] || !res[1]

# グラフに出力
@graph << res
# ゴールデンクロス/デッドクロスを判定
@cross.next_data(*res)

do_trade

end

@unageanu
Copy link
Owner

その方針でも大丈夫です。この場合、 next_tick を 先頭で return 等して2回に1回スキップすれば、30秒に1回処理するようにできます。こちらの方が他のエージェントに影響しないので良いかと思います。

@JunyaW
Copy link
Author

JunyaW commented Nov 28, 2017

ありがとうございます。この方針でいろいろトライしてみようと思います。

ちなみに、こうした方法でnext_tickの間隔を1時間毎などに設定し実際に口座に適応した時には、バックテストでレート間隔を1時間毎にした時と同様に、このエージェントは動くと考えてよろしいのでしょうか? それとも少し違うのでしょうか?

@unageanu
Copy link
Owner

レート間隔を1時間毎にした時

2回に1回スキップする方式だと、レート間隔を1時間した場合は2時間に1回の呼び出しになりますね・・・。tick#timestamp をチェックして、前回の next_tick から既定の時間経過していたら後続の処理を呼び出す方式にすれば、この場合も期待通りの動作になると思います。

@JunyaW
Copy link
Author

JunyaW commented Nov 28, 2017

素早い返信ありがとうございます。

関連する質問なのですが、仮に1時間毎の動作にした場合、交差状態の判断をするときに呼び出される直近の先行および遅行指標というのは、1時間前に呼び出したときのものになりますか。それとも、15秒前のものになりますか?

@unageanu
Copy link
Owner

この場合、1時間前に呼び出したときのものになります。

@JunyaW
Copy link
Author

JunyaW commented Dec 1, 2017

以下のようにnext_tick(tick)を書き換えてみたのですが、バックテストでエラーが出てしまいます。どうやら、前回のnext_tickのtimestampが呼び出せない状態のようなのですが、なにか改善するための方針などはあるでしょうか?

def next_tick(tick)
timestamp = tick.timestamp
timestamp_prev = tick_prev.timestamp
return if (timestamp.hour - timestamp_prev.hour) < 1
# 移動平均を計算
res = @mvs.map { |mv| mv.next_data(tick[:USDJPY].bid) }
return if !res[0] || !res[1]

# グラフに出力
@graph << res
# ゴールデンクロス/デッドクロスを判定
@cross.next_data(*res)

do_trade

end

@unageanu
Copy link
Owner

unageanu commented Dec 1, 2017

バックテストでエラーが出てしまいます。

どんなエラーが出ていますでしょうか?

@JunyaW
Copy link
Author

JunyaW commented Dec 2, 2017

以下のようなエラーが出てしまいます。

E, [2017-12-01T12:20:44.725738 #4] ERROR -- : undefined local variable or method tick_prev' for #<#<Module:0x00000002807a08>::MovingAverageAgent:0x00000004165950> (NameError) agent/moving_average_timestamp_agent.rb:45:in next_tick'
/app/src/jiji/model/agents/agents.rb:35:in block in next_tick' /app/src/jiji/model/agents/agents.rb:33:in each'
/app/src/jiji/model/agents/agents.rb:33:in next_tick' /app/src/jiji/model/trading/jobs/notify_next_tick_job.rb:17:in exec'
/app/src/jiji/model/trading/jobs/notify_next_tick_job.rb:74:in exec' /app/src/jiji/model/trading/process.rb:37:in do_next_job'
/app/src/jiji/model/trading/process.rb:30:in run' /app/src/jiji/model/trading/process.rb:24:in block in start'
/app/vendor/bundle/ruby/2.2.0/gems/thread-0.2.2/lib/thread/pool.rb:67:in call' /app/vendor/bundle/ruby/2.2.0/gems/thread-0.2.2/lib/thread/pool.rb:67:in execute'
/app/vendor/bundle/ruby/2.2.0/gems/thread-0.2.2/lib/thread/pool.rb:405:in block (2 levels) in spawn_thread' /app/vendor/bundle/ruby/2.2.0/gems/thread-0.2.2/lib/thread/pool.rb:372:in loop'
/app/vendor/bundle/ruby/2.2.0/gems/thread-0.2.2/lib/thread/pool.rb:372:in `block in spawn_thread'

@unageanu
Copy link
Owner

unageanu commented Dec 2, 2017

エラーメッセージに記載されている通り、 tick_prev への代入が必要ですね。
以下を試してみてください。

def next_tick(tick)
  return if (!@tick_prev.nil? && tick.timestamp >= @tick_prev.timestamp  + 60 * 60)

  @tick_prev = tick

  # 移動平均を計算
  res = @mvs.map { |mv| mv.next_data(tick[:USDJPY].bid) }
  return if !res[0] || !res[1]

   # グラフに出力
  @graph << res
  # ゴールデンクロス/デッドクロスを判定
  @cross.next_data(*res)

  do_trade
end

@JunyaW
Copy link
Author

JunyaW commented Dec 2, 2017

ありがとうございました。言われたように書き換えると、バックテストのエラーが出なくなり、完了するようになりました。

しかし、このエージェントを使用してもdo tradeされる間隔が1時間毎にはなっていないようで、
バックテストの結果は15秒でdo tradeしたものと全く同じ結果になってしまいました。
(おそらくreturn if が機能していないということですが、自分が読む限り、このreturn ifは機能するように見えます。)

どこか他に変更すべき箇所はあるのでしょうか?

def next_tick(tick)
return if (!@tick_prev.nil? && tick.timestamp >= @tick_prev.timestamp + 60 * 60)

@tick_prev = tick

# 移動平均を計算
res = @mvs.map { |mv| mv.next_data(tick[:USDJPY].bid) }
return if !res[0] || !res[1]

# グラフに出力
@graph << res
# ゴールデンクロス/デッドクロスを判定
@cross.next_data(*res)

do_trade

end

@unageanu
Copy link
Owner

unageanu commented Dec 3, 2017

とりあえずデバッグログを埋め込んで、以下を確認してみてください。

  • do_trade の呼び出しが15分ごとになっていること
  • if 文の条件判定 tick.timestamp >= @tick_prev.timestamp + 60 * 60 がどう評価されているか

@JunyaW
Copy link
Author

JunyaW commented Dec 3, 2017

デバッグログを埋め込むには、 logger.debug "test"  をどこに書き加えれば良いでしょうか?
とりあえず、def next_tick(tick)のdo tradeのあとに入れてみたのですが、確認したい情報がログで見られていないです。

@unageanu
Copy link
Owner

unageanu commented Dec 4, 2017

logger.debug "test"  をどこに書き加えれば良いでしょうか?

  • do_tradeのあと
  • do_tradeの前
  • next_tick(tick) の先頭
  • post_create の先頭

あたりでどうでしょうか?

@JunyaW
Copy link
Author

JunyaW commented Dec 5, 2017

ありがとうございます。ご指摘の4箇所にそれぞれ、loggerを入れてテストしてみました。
post_create の先頭 - test1
next_tick(tick) の先頭 - test2
do_tradeの前 - test3
do_tradeのあと - test4
としてみました。

すると、ログにはtest1のあと、test2が75回ほどつづいてから、test2, test3, test4が終わりまで繰り返されました。

また、tick.timestamp >= @tick_prev.timestamp + 60 * 60 の 60 * 60の部分を6 * 6 にしても、666 * 666にしても表示されるログは 60 * 60の場合と変わりませんでした。

しかし、0 * 0にした場合には、test2がずっと続いて、test3とtest4は出て来ずに、取引も一度もされていませんでした。

取り急ぎ、ご報告まで。自分でも考えてみます。
なにか考えられる事がありましたら、ご指摘宜しくお願いします。

@JunyaW
Copy link
Author

JunyaW commented Dec 5, 2017

0 * 0, 1 * 1, 10 * 1などのときは、test2がずっと続きます。

10 * 10にすると60 * 60と同じ様になります。

@unageanu
Copy link
Owner

unageanu commented Dec 5, 2017

test2が75回ほどつづいてから、test2, test3, test4が終わりまで繰り返されました。

この場合、期待通り動作しているように思いますがどうでしょうか?

自分でも考えてみます。

頑張ってください。

@JunyaW
Copy link
Author

JunyaW commented Dec 5, 2017

コメントありがとうございます。

1222..(x70-75)34234234.....というふうになっているということは、一番最初のnext_tickまで75回ほどスキップされて、その後は15秒間隔で動いているということかと思うのです。

本来は、12342..(x240)342..(x240)342..(x240)342..(x240)..というふうに続くのかと思っていたのですが。
(x240) = 15 sec x 240 = 1hour

このログの読み方で誤解しているところはあるでしょうか?

@unageanu
Copy link
Owner

unageanu commented Dec 5, 2017

このログの読み方で誤解しているところはあるでしょうか?

あっていると思います。
となると、

return if !res[0] || !res[1]

で抜けているのかもしれませんね。

@JunyaW
Copy link
Author

JunyaW commented Dec 6, 2017

ご指摘の通り、サンプルのエージェントでも最初の75回程度 return if !res[0] || !res [1]のところでreturnされていました。そのため、この最初にreturnされ続ける現象は今回の改定とは直接関係ないかもしれません。(理由がありましたら、教えていただきたいです。)

次に、!@tick_prev.nil? && tick.timestamp >= @tick_prev.timestamp + 60*60のところですが、+されるの値が15以下の場合は、最初の1回のみ、この式は通過し、その後のreturn if !res[0] || !res [1]のところまでいってreturnされます。その後は、このreturn ifでずっとreturnされて取引が行われません。

16以上の場合は、サンプルエージェントと同様、この評価式は常に通り、最初の75回くらいはreturn if !res[0] || !res [1]のところでreturnされたあとに、その後は15秒間隔の取引が行われていました。

なぜ15以下の場合にこの評価式が最初の1回だけ通って、16以上の場合には常に通るようになるのでしょうか?
なにか考えられることがあれば宜しくお願いします。 

@unageanu
Copy link
Owner

unageanu commented Dec 6, 2017

なるほど、条件式が逆になっているのが原因のようですね。失礼しました。

return if (!@tick_prev.nil? && tick.timestamp < @tick_prev.timestamp + 60 * 60)

を試してみてください。

@JunyaW
Copy link
Author

JunyaW commented Dec 7, 2017

評価式の確認をしていただき、ありがとうございました。

next_tickの先頭に
return if (!@tick_prev.nil? && tick.timestamp < @tick_prev.timestamp + 60 * 60)
@tick_prev = tick
を入れることで、next_tickの間隔を変えることができることをバックテストで確認しました。

また、ささいなことなのですが、エージェントの開始時に、return if !res[0] || !res[1]で長期移動平均線の日数分だけreturnされてから、crossの判定が始まることを確認しました。
(なので、長期移動平均線の設定を30日にして、6時間毎にnext_tickすることにすると、6時間 * 30 = 180時間、およそ最初の約1週間は待ち時間になってしまうみたいです。)

念のため、確認なのですが、一度エージェントを動かしてしまえば2ヶ月でも3ヶ月でもそのまま動き続けるのでしょうか? それとも1ヶ月ごとにエージェントの再起動などがあるのでしょうか?

@unageanu
Copy link
Owner

unageanu commented Dec 7, 2017

一度エージェントを動かしてしまえば2ヶ月でも3ヶ月でもそのまま動き続けるのでしょうか?

Jijiの再起動等を行わなければ、そのまま動き続けます。

@JunyaW
Copy link
Author

JunyaW commented Dec 8, 2017

ありがとうございます。また何かおたずねすることがあると思いますが、宜しくお願い致します。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants