0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DrRacketで仮想通貨の自動売買してみたい

Last updated at Posted at 2022-05-27

bitFlyerのAPIを使って、自動売買のプログラミングに挑戦しました。
なぜRacket(Scheme)なの?と思わるかもしれませんが、理由は好きだからです。
金融云々は、素人です。
好きなように書いてます。

#lang racket

;;; -------------------------------------------------------------------------------

(define-syntax (if-it stx)
  (syntax-case stx ()
    [(if-it pred expr then else)
     (with-syntax [(it (datum->syntax #'if-it 'it))]
       #'(let ([it expr])
           (if (pred it)
               then
               else) ) ) ] ) )


(define-syntax (loop stx)
  (syntax-case stx ()
    [(loop expr ...)
     (with-syntax ([exit (datum->syntax #'loop 'exit)])
       #'(let/cc exit
           (let loop ()
             expr
             ...
             (loop) ) ) ) ] ) )

;;; -------------------------------------------------------------------------------

(module CryptoWatch racket

  (provide get-cryptowatch
           collect-price)
 
  (require net/http-easy)  ; raco pkg install http-easy


  (define (get-cryptowatch url)
    (let ([response (response-json (get url))])
    
      (if (eq? 'error (cadr (hash-keys response)))
          '()
          (hash-ref (hash-ref response 'result) '|300|)) ) )

  
  (define (collect-price-ohlc menu data)
    (match menu
      ['open  (map second data)]
      ['high  (map third  data)]
      ['low   (map fourth data)]
      ['close (map fifth  data)] ) )


  (define (collect-price menu data [term 0])
    (let ([prices (collect-price-ohlc menu data)])
      (if (zero? term)
          prices
          (take-right prices term) ) ) )
  
  )  ; module

;;; -------------------------------------------------------------------------------

(module Send-bitFlyer racket

  (provide send-order)

  (require gregor
           json
           net/http-easy  ; raco pkg install http-easy
           rnrs/bytevectors-6
           sha      ; raco pkg install sha
           timable  ; raco pkg install timable
           )

  
  (define (create-header method
                         endpoint
                         body
                         api-key
                         api-secret
                         [content-type "application/json"])
    
    (let* ([timestamp (datetime->iso8601 (current-datetime))]

           [message   (string-append timestamp method endpoint body)]

           [signature (bytes->hex-string
                       (hmac-sha256 (string->utf8 api-secret)
                                    (string->utf8 message) ) )] )

      (hasheq 'ACCESS-KEY       api-key
              'ACCESS-TIMESTAMP timestamp
              'ACCESS-SIGN      signature
              'Content-Type     content-type) ) )


  (define (send-order base-url
                      endpoint
                      currency-pair
                      api-key
                      api-secret
                      [child_order_type "MARKET"]
                      [minute_to_expire "10000"]
                      [time_in_force    "GTC"] )

    (λ (side size)    
      (let* ([body (jsexpr->string
                    (hasheq 'product_code     currency-pair
                            'child_order_type child_order_type
                            'side             side
                            'size             size
                            'minute_to_expire minute_to_expire
                            'time_in_force    time_in_force) ) ]

             [headers (create-header "POST" endpoint body api-key api-secret)] )

        (response-json
         (post (string-append base-url endpoint)
               #:headers headers
               #:data    body) ) ) ) )

  )  ; module

;;; -------------------------------------------------------------------------------

(module MA racket

  (provide sma
           ema
           macd)
           
  
  (define-syntax sum
    (syntax-rules ()
      [(_ lst)
       (for/sum ([x lst]) x) ]

      [(_ proc lst)
       (for/sum ([x lst])
         (proc x) ) ] ) )


  (define (ave lst)
    (/ (sum lst)
       (length lst) ) )


  (define (sma lst)
    (ave lst) )


  ;; 前日の指数平滑移動平均 + α × (当日終値-前日の指数平滑移動平均)
  ;; α(平滑定数) = 2 ÷ (n + 1)
  (define (ema lst p)
    (let ([alpha (/ 2 (add1 (length lst)))])
      (+ (car lst)
         (* alpha
            (- p (car lst) ) ) ) ) )
  
  
  ;; 意味が分かっていません
  ;; 勝手な解釈です
  (define (macd lst0 lst1)
    (- (sma lst0)
       (sma lst1) ) )
      
  )  ; module

;;; -------------------------------------------------------------------------------

(require 2htdp/batch-io
         json
         racket/generic)

(require 'CryptoWatch
         'Send-bitFlyer
         'MA)

;;; -------------------------------------------------------------------------------

(define-generics traded-status
  (buy?    traded-status)
  (sell?   traded-status)
  (update! traded-status) )


(struct Traded-Status (flag)
  #:mutable
  #:transparent
  #:methods gen:traded-status

  [(define (buy? ts)
     (eq? 'BUY (Traded-Status-flag ts)) )

   (define (sell? ts)
     (eq? 'SELL (Traded-Status-flag ts)) )

   (define (update! ts)
     (let ([_ts (Traded-Status-flag ts)])

       (when (eq? 'SELL _ts)
         (set-Traded-Status-flag! ts 'BUY) )

       (when (eq? 'BUY _ts)
         (set-Traded-Status-flag! ts 'SELL) ) ) )
   
   ]  ; methods
  )  ; struct

;;; ------------------------------------------------------------------------------

(define-generics stack-ema
  (stack-null?   stack-ema)  
  (init-stack!   stack-ema close-prices)  
  (push-stack!   stack-ema most-recent-price)
  (update-stack! stack-ema leng)
  (calc-macd     stack-ema) )
  

(struct Stack-EMA (value)
  #:mutable
  #:transparent
  #:methods gen:stack-ema

  [(define (stack-null? stck)
     (null? (Stack-EMA-value stck)) )


   (define (init-stack! stck prices)
     (set-Stack-EMA-value!
      stck
      (cons (sma prices)
            (Stack-EMA-value stck)) ) )

   
   (define (push-stack! stck most-recent)
     (set-Stack-EMA-value!
      stck
      (cons (ema (Stack-EMA-value stck)
                 most-recent)
            (Stack-EMA-value stck)) ) )


   (define (update-stack! stck leng)
     (let ([lst (Stack-EMA-value stck)])
       
       (when (> (length lst) leng)
         (set-Stack-EMA-value!
          stck
          (take lst leng) ) ) ) )


   (define (calc-macd stck)
     (let* ([lst  (Stack-EMA-value stck)]
            [leng (length lst)] )
       
       (if (>= leng 10)
           (begin
             (when (odd? leng)
               (set! lst  (drop-right lst 1))
               (set! leng (length lst)) )
  
             (macd (take lst (/ leng 2))  ; short
                   lst) )  ; long
           0) ) )
     
   ]  ; methods
  )  ; struct
     
;;; -------------------------------------------------------------------------------

(define *key-settings*
  (with-input-from-string
      (read-file "./settings/key-settings.json")
    (λ () (read-json)) ) )


(define *url-cryptowatch*
  "https://api.cryptowat.ch/markets/bitflyer/xrpjpy/ohlc?periods=300")


(define *send-order*
  (send-order "https://api.bitflyer.com"
              "/v1/me/sendchildorder"
              "XRP_JPY"
              (hash-ref *key-settings* 'api-key)
              (hash-ref *key-settings* 'api-secret) ) )


(define *traded-status* (Traded-Status 'BUY))

(define *stack-ema* (Stack-EMA '()))

;;; -------------------------------------------------------------------------------

(define (main)
  (loop 
   (let* ([data-cryptowatch
           (if-it null? (get-cryptowatch *url-cryptowatch*)
                  (exit 'Abort)
                  it) ]

          [most-recent-price
           (fifth (last data-cryptowatch)) ]
       
          [macd   null]
          [result null] )
  
     ;; スタックの操作 判断
     (if (stack-null? *stack-ema*)
         ;; 初回のみ
         (init-stack! *stack-ema*
                      (drop-right (collect-price 'close data-cryptowatch 21)
                                  1) )

         ;; 2 回目以降
         (push-stack! *stack-ema* most-recent-price) )


     ;; 更新
     (set! macd (calc-macd *stack-ema*))


     ;; 売買
     (cond
       [(and (sell? *traded-status*) (negative? macd))

        (*send-order* "SELL" "1.0")
        (update! *traded-status*)
        (set! result "売った") ]

       [(and (buy? *traded-status*) (positive? macd))

        (*send-order* "BUY" "2.0")
        (update! *traded-status*)
        (set! result "買った") ]

       [else
        (set! result "待機") ] )


     ;; 表示
     (displayln (format "
MOST RECENT  :  ~s
MACD         :  ~s
~s

~s
"
                        most-recent-price
                        macd
                        *traded-status*
                        result) )

     (displayln (make-string 60 #\-))


     ;; 更新
     (update-stack! *stack-ema* 20) )


   ;; 待機
   (sleep 900) ) )  ; 15 分
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?