초보자용 암호화폐 양적 거래 - 암호화폐 양적 거래에 더 가까워지도록 (2)

저자:리디아, 창작: 2022-07-27 16:34:41, 업데이트: 2023-09-24 19:31:16

img

초보자용 암호화폐 양적 거래 - 암호화폐 양적 거래에 더 가까워지도록 (2)

지난 기사에서 우리는 프로그래밍 트레이딩 스크립트에 대해 이야기했습니다. 사실, 거래 전략은 거래 스크립트 프로그램입니다. 기사에서는 주로 거래 스크립트 프로그램 (프로그램이 실행되는 곳) 에 대한 하드웨어 캐리어의 필요성에 대해 이야기하고 스크립트 거래 프로그램이 어떤 종류의 컴퓨터 프로그래밍 언어로 작성 될 수 있는지에 대해 이야기합니다. (FMZ 퀀트 트레이딩 플랫폼에서 사용되는 세 가지 프로그래밍 언어가 나열되어 있습니다. 물론, 프로그래밍 언어를 사용하여 프로그래밍 트레이딩 전략을 구현할 수 있습니다.) 이 기사에서는 암호화폐의 정량화에 대해 계속 논의하고 그것에 대해 알아봅니다.

프로그램 트레이딩 스크립트

  • 거래 전략의 종류 프로그래밍 트레이딩과 양적 트레이딩에 처음 시작하는 사람들은 다양한 트렌드 전략, 중재 전략, 고주파 전략, 그리드 전략 등과 같은 용어에 혼란을 겪을 수 있습니다. 실제로 프로그래밍 트레이딩과 양적 트레이딩에서 일반적인 유형의 전략은 단순히 여러 방향입니다.

    • 중재보험 전략 간단히 말해서, 짧은 포지션을 보유하면서 긴 포지션을 보유하는 전략은 기본적으로 중재 전략으로 분류 될 수 있습니다. 스팟 크로스 마켓, 선물 크로스 기간, 선물 및 스팟 중재 및 크로스 종 중재와 같은 많은 특정 유형이 있습니다.
    • 트렌드 전략 간단히 말해서, 트렌드를 추적하는 전략으로 두 배 이동 평균, MACD 및 기타 전략과 같은 주문을 배치하고 포지션을 보유합니다.
    • 회귀 전략 예를 들어, 전력망 전략, 변동적인 시장에서 가격 변동으로 수익을 창출.
    • 고주파 전략 간단히 말해서, 그것은 시장의 미세 구조, 패턴, 기회 등을 발견하기 위해 일부 알고리즘을 통해 높은 주파수 거래를위한 전략입니다.

    위의 내용은 거래 전략의 관점에서 나뉘어 있습니다. FMZ 양자 거래 플랫폼에서 전략 설계의 관점에서 전략은 다음과 같이 나눌 수 있습니다.

    • 단일 품종 전략 즉, 이 전략은 BTC 거래 또는 ETH 거래와 같은 하나의 종만을 운영합니다.
    • 다종 전략 간단히 말해서, 그것은 전략적 논리에 따라 여러 종을 운영하는 것입니다.
    • 여러 계정 전략 간단히 말해서, 여러 교환 객체는 실제 봇에서 구성됩니다. (거래의 개념은 이전 기사에서 소개되었으며, API KEY가 구성된 교환 객체는 교환 계정을 나타냅니다.) 예를 들어, 일부 주문을 따르는 전략에서는 여러 계정이 함께 작업을 수행합니다. 간단히 말해서, 여러 교환 객체 (회계) 는 실제 봇에서 관리됩니다.
    • 다중 논리 전략 예를 들어, MACD 전략, 이동 평균 전략, 그리드 전략 등은 실제 봇에서 동시에 설계됩니다 (물론, 그것은 다른 교환 객체를 작동하는 것입니다, 동일한 교환 객체의 작동은 특정 전략이 논리적으로 충돌하는지 여부에 달려 있습니다)
  • Exchange API 인터페이스 프로그래밍 트레이딩 스크립트는 거래소 계정을 어떻게 운영합니까? 거래소가 열었던 API 인터페이스를 통해입니다. 그래서 어떤 종류의 인터페이스가 교환에 열려 있습니까? 이전 기사에서 우리는 교환에 대해 이야기했습니다 REST와 웹소켓 인터페이스 일반적으로 Exchange 섹션에서. 여기 우리는 전략 절차 수준에서 몇 가지 개념을 추가합니다. 교환 인터페이스는 유효성 여부에 따라 나뉘어 있습니다 (REST와 웹소켓 모두), 검증과 검증이 없습니다.

    • 확인을 필요로 하지 않는 인터페이스 일반적으로 공중 인터페이스로 알려진 이 유형의 인터페이스는API KEY이 유형의 인터페이스는 일반적으로 시장 인터페이스입니다. 예를 들어 심층 시장 가격, K-라인 데이터, 자금 조달율, 거래 품종에 대한 정보 조회, 거래 서버 시간표 조회 등. 간단히 말해서, 당신의 계정과 관련이 없는 인터페이스는 대략적으로 공개 인터페이스로 결정될 수 있습니다.
      FMZ 퀀트 트레이딩 플랫폼에서 확인되지 않은 API 함수를 호출할 때 (거래소의 확인되지 않은 인터페이스, 공개 인터페이스를 캡슐화) API KEY 구성이 잘못되었더라도 인터페이스에서 반환된 데이터는 정상적으로 얻을 수 있습니다.

    • 확인을 필요로 하는 인터페이스 간단히 말해서, 확인해야 하는 인터페이스 (API KEY를 통해), 이러한 종류의 인터페이스는 개인 인터페이스라고 불립니다. 일반적으로 계정 자산 조회, 계정 위치 조회, 미결 주문 조회, 송금 조회, 통화 전송, 레버리지 조정, 위치 모드 설정 등과 같은 계정의 일부 작업 또는 정보와 관련이 있습니다. 이 모든 작업은 검증되어야 합니다. FMZ 퀀트 트레이딩 플랫폼에서 확인해야 하는 API 함수를 호출할 때 (집약된 교환, 개인 인터페이스에 대한 확인이 필요한 인터페이스), API KEY가 잘못 구성되면 인터페이스가 호출될 때 오류가 보고되고 null 값이 반환됩니다.

    FMZ 양자 거래 플랫폼에서 이러한 인터페이스는 어떻게 사용됩니까?

    FMZ 양자 거래 플랫폼은 교환 행동과 인터페이스를 일관된 정의와 함께 포괄합니다 (예를 들어 K-라인 인터페이스, 심층 시장 인터페이스, 현재 자산 질의 인터페이스, 주문 인터페이스, 주문 취소 인터페이스 등), 이러한 인터페이스는 FMZ 양자 거래 플랫폼의 API 기능으로 불립니다.https://www.fmz.com/api).

    그렇다면 FMZ 양자 거래 플랫폼에서 사용되는 다른 행동과 정의와 교환 인터페이스가 어떻게 작동합니까?

    이 거래소 인터페이스에는 자산 전송, 조건부 주문, 대량 주문 배치, 대량 주문 취소, 주문 수정 등이 포함됩니다. 일부 거래소에는 이러한 인터페이스가 있으며 일부는 그렇지 않으며 기능과 사용 세부 사항은 상당히 다를 수 있으므로 이러한 인터페이스에는exchange.IOFMZ 퀀트 트레이딩 플랫폼의 기능 ( 자세한 내용은 FMZ 퀀트 트레이딩 플랫폼 API 문서를 참조하십시오.)https://www.fmz.com/api#exchange.io..또한 FMZ 양자 거래 플랫폼 전략 광장에서 몇 가지 실용적인 IO 예시 전략이 있습니다.

    FMZ 퀀트 트레이딩 플랫폼 API 문서의 모든 API 함수는 네트워크 요청을 생성합니까?

    우선, 거래소의 API 인터페이스는 액세스 주파수 제한이 있습니다 (예를 들어 초당 5 번), 액세스 빈도가 너무 많을 수 없습니다. 그렇지 않으면 http 429 오류를 보고하고 접근이 거부 될 것입니다. (대부분의 거래소에서 429 보고). FMZ 양자 거래 플랫폼의 모든 API 기능은 네트워크 요청을 생성하지 않습니다. 그들 중 일부는 현재 거래 쌍을 설정하고 계약 코드를 설정하고 지표 계산 기능을 설정하고 교환 객체 이름을 얻는 것과 같은 일부 로컬 설정을 수정합니다. 일반적으로, 네트워크 요청이 함수의 목적에서 발생하는지 판단 할 수 있습니다. 교환 데이터, 교환 계정 작업 및 기타가 생성 된 네트워크 요청일 때, 이러한 인터페이스는 호출 주파수에주의를 기울여야합니다.

    • FMZ 양자 거래 플랫폼에서 API 기능을 사용할 때 몇 가지 일반적인 문제와 경험에 대해 이야기하자

      • 오류 허용 이것은 가장 흔한 오류입니다. 무수히 많은 초보자를 괴롭혔습니다. 전략 백테스팅의 모든 것은 종종 정상입니다. 왜 실제 봇이 잠시 동안 실행되고 (어떤 시점에서도 활성화 될 수 있습니다.)

        img

        전략을 작성할 때, 우리는 모두 인터페이스에 의해 반환 된 데이터를 판단하고 확인해야합니다. 예를 들어 FMZ 퀀트 트레이딩 플랫폼에서 얻을 수있는 시장 가격 코드의 라인 (자신으로 직접 거래소 인터페이스에 액세스하는 프로그램을 작성하는 것과 동일합니다):var ticker = exchange. GetTicker(), 우리가 사용해야 할 경우Last(마지막 가격)ticker변수 (GetTicker 함수가 반환하는 구조를 참조), 우리는 사용해야 합니다var newPrice = ticker.Last이런 데이터를 얻기 위해 (newPrice란 무엇인가? newPrice: latest, Price: price, yes!GetTicker()기능은 정상 데이터로 돌아갑니다, 괜찮습니다, 하지만 요청 타임 아웃, 네트워크 오류가 있다면, 교환은 네트워크 케이블을 당겨, 케이블이 잘라, 아이가 전기 스위치를 당겨, 등...GetTicker()함수로 돌아가기null현재,tickernull, 그리고 내가 접속하면Last, 프로그램 예외가 발생하고 전략 프로그램이 중지됩니다. 그것은 인터페이스 호출의 실패 (GetTicker 호출 실패 null를 반환) 는 전략의 정지 직접적인 이유가 아닌 것 같습니다null인터페이스 호출 실패의 오류 보고는 실제 봇 정지 (중고) 를 유발하지 않습니다. 그렇다면 실제 로봇의 비정상적인 정지 현상을 방지하기 위해 어떻게 할 수 있을까요? 답은 인터페이스에서 반환된 데이터에 대한 오류 용인 처리 수행입니다. 그것은 매우 간단합니다, 그냥 반환 된 데이터가null(자바스크립트 언어의 예, 다른 언어는 일반적으로 동일) 설명에 대한 짧은 코드 세그먼트를 작성 (이것은 단지 설명입니다, 당신은 직접 실행 할 수 없습니다!)

        var ticker = exchange.GetTicker()
        if (ticker) {
            var newPrice = ticker.Last
            Log("Print the latest price:", newPrice)
        } else {
            // The data is null, there will be no problem if no operation is performed
        }
        

        뿐만 아니라GetTicker인터페이스는 오류 용인성이 있어야 하지만 네트워크 요청과의 인터페이스는 반환 값에 대해 오류 용인성이 있어야 합니다 (함수의 반환 값을 사용하는 경우) 많은 오류 용인 방법이 있습니다, 당신은_C()함수 (FMZ API 문서를 참조) 를 작성하여 오류 용인 함수 및 오류 용인 메커니즘 및 논리를 직접 설계합니다. 사용에 대해_C()함수, 많은 초보자가 잘못 사용합니다._C()function은 함수 참조가 아니라 함수 호출입니다. 일반적 용어로:_C(funcName, param1, param2), 호출이 정확하고, funcName는 괄호가 없고, param1과 param2는 funcName 함수로 전달되는 매개 변수입니다._C(funcName(param1, param2)), 호출은 잘못, 일반적으로 FMZ API 문서를 진지하게 읽지 않는 초보자들에 의해 작성됩니다.

      • 포트 시장 구매 주문의 주문 양 포트 시장 주문 구매 주문의 주문 양은 또한 초보자에 의해 실수를 쉽게, 이전 기사에서 언급했듯이, 포트 시장 주문 구매 주문의 주문 양은 일반적으로 금액입니다 (많은 거래소가 다른 설정이 될 수 있습니다, 일반적으로, FMZ에 대한 이러한 특수 교환 설정은 FMZ API 문서에서 설명 될 것입니다), 예를 들어, 나는 테스트를 위해 OKEX V5 데모를 사용합니다: 거래 쌍은 다음과 같이 설정됩니다.LTC_USDT

        function main() {
            exchange.IO("simulate", true)   // Switch to the demo of OKEX exchange
            exchange.Buy(-1, 1)             // The price is -1, indicating that the order placed is a market order, and the quantity is 1, indicating that the order amount is 1USDT
        }
        

        거래소는 일반적으로 주문 금액에 제한을 가지고 있기 때문에, 제한보다 작은 주문은 배치되지 않습니다 (예를 들어, Binance Spot는 성공적으로 배치되기 전에 5USDT 이상의 각 주문이 필요합니다). 따라서 다음과 같은 주문을하면 오류를 보고합니다.

        Error	Buy(-1, 1): map[code:1 data:[map[clOrdId: ordId: sCode:51020 sMsg:Order amount should be greater than the min available amount. tag:]] msg:]
        
      • 향후 주문을 하는 방향 선물 전략을 만들 때, 주문을 배치하는 방향은 초보자들에 의해 종종 실수로 인해 문제가 발생합니다. 예를 들어 FMZ 퀀트 트레이딩 플랫폼에서 전략을 작성하십시오. 먼저 API 문서에 있는 설명을 살펴봅시다.https://www.fmz.com/api#exchange.setdirection...

        img

        순서 함수는Buy, Sell그러나, 선물 (물론, 스팟에 문제가 없습니다, 스팟은 단지 구매 및 판매) 는 긴 오픈, 긴 폐쇄, 짧은 오픈 및 짧은 폐쇄의 방향을 가지고, 그래서 그것은 구매/판매는 그렇게 많은 방향으로 작업을 표현할 수 없습니다.exchange.SetDirection(), 미래에셋 거래 방향을 설정합니다. FMZ에서exchange.SetDirection("buy")(방향을 먼저 설정)exchange.Buy, 그것은 배치 된 명령이 긴 지위를 열기 위한 명령이라는 것을 의미합니다. 그리고 그 밖의 것들:exchange.SetDirection("sell")이 약과 함께exchange.Sell즉, 지명된 거래는 짧은 거래를 개시하는 거래입니다.exchange.SetDirection("closebuy")이 약과 함께exchange.Sell, 그것은 배치 된 명령이 긴 위치를 닫는 명령이라는 것을 의미합니다.exchange.SetDirection("closesell")이 약과 함께exchange.Buy즉, 지명된 거래는 짧은 거래를 종료하는 거래입니다. 초보자들은 보통exchange.SetDirection("sell")이와 함께exchange.Buy, 또는 다른 잘못된 조합. 그러면 오류가 보고됩니다 (백테스팅은 오류를 보고하지 않을 수 있지만 이것은 분명히 논리적 오류입니다. 강박 장애는 용납 할 수 없습니다...). 초보자 들 이 흔히 저지르는 또 다른 실수

        function main() {
            exchange.SetContractType("quarter")   // Set the current contract as a quarterly contract
            exchange.SetDirection("sell")
            var id = exchange.Sell(-1, 1)    
            Log("See my market order is placed and the transaction is completed, there is a position", exchange.GetPosition())    
            exchange.SetDirection("closebuy")   // closebuy is used in conjunction with Sell, yes~
            exchange.Sell(-1, 1)
        }
        

        img
        여기 당신은 질문 할 수 있습니다: 나는 왜 포지션을 가지고 closebuy와 Sell도 함께 사용합니까, 왜 나는 오류를 받고 포지션을 닫을 수 있습니까? 나는 대답합니다: 당신은 잘못된 방향으로 닫았습니다! 긴 포지션은 닫아야합니다. 위의 오류 보고에서 가능한 상황 중 하나는: 닫기 방향이 올바르게 설정되고, 명령 함수가 올바르게 사용되고, 이 방향의 위치도 유지되지만 오류가 여전히 보고됩니다. 그 이유는 프로그램에서 여러 개의 오더를 올렸지만 초기 오더는 채우지 않았으며, 클로저 오더가 시장에서 미뤄지고 있기 때문입니다. 이 시점에서 프로그램이 포지션을 계속 닫고 있으며, 클로저 포지션을 초과하는 오류가 표시됩니다.

      • 로그 출력, 거래 정보 표시 프로그래밍 및 양적 거래 전략의 설계는 "데이터 디스플레이" 및 "운동 로그 출력"과 같은 인간-컴퓨터 상호 작용의 설계와 떼려야?? 수 없습니다. 우리는 일반적으로 실제 봇 스크립트 및 전략 프로그램을 작성하기 위해 네이티브 프로그래밍 언어를 사용합니다. 현재 언어의 출력 기능은 직접 사용됩니다. 예를 들어: python 사용print... 자바스크립트 사용console.log... 골랑 사용fmt.Println()... C++ 사용cout

        FMZ 플랫폼의 정보 디스플레이에 대해 이야기 해 봅시다. FMZ 양자 거래 플랫폼에는 정보가 표시되는 두 가지 주요 장소가 있습니다.

        • 상태 열 실제 봇이 실행되면 실제 봇 페이지가 그림과 같습니다.

          img

          표시 부분은 상태 열 정보입니다. 상태 열은 주로 실시간으로 변경되는 데이터를 표시하는 데 사용됩니다. (실시간 변경 사항이 실시간으로 관찰되어야하고 매번 로그로 인쇄 할 수 없기 때문에 이러한 유형의 데이터는 상태 열에서 표시 할 수 있습니다. 로그는 중복되고 의미없는 데이터를 반복하여 각 로그가 인쇄되면 질의에 영향을 미칩니다.) 상태 열에 표시된 데이터는LogStatus자세한 내용은 FMZ API 문서를 참조하십시오.

        • 로그 열 또한 실제 봇 페이지에서 제거되었습니다. 그림과 같이:

          img

          표시 부분은 로그 열입니다. 로그 열은 주로 특정 시간에 특정 데이터를 영구적으로 기록하거나 특정 시간에 특정 전략의 작업을 기록하는 데 사용됩니다. 여러 종류의 로그가 있습니다.

          1. 공통 로그, FMZ에 있는 전략은 로그 함수를 채택하여 전략 로그에 출력하고 인쇄합니다.

            img

          2. 주문 로그, 사용exchange.Sell/exchange.BuyFMZ의 전략에서 로그 출력 자동으로 기록합니다.

            img

          3. 취소 로그exchange.CancelOrderFMZ의 전략에서 사용되며, 로그에서 취소 로그를 자동으로 출력합니다.

            img

          4. 오류 로그, FMZ에서 전략이 실행될 때, 네트워크 요청을 하는 인터페이스에서 호출 오류가 발생하고, 예외가 던집니다 (던지 선언과 같이), 오류 로그는 로그에서 자동으로 출력됩니다.

            img

        FMZ에 있는 API 함수, 로그 (Log) 외출을 생성할 수 있는 함수, 교환 (exchange.Buy ((Price, Amount), 교환 (exchange.CancelOrder ((Id), 등, 이 모든 함수들은 필요한 매개 변수들, 예를 들어: 교환 (exchange). 취소 (cancelOrder)) 명령어 (j). 아이디, 명령어 (j) 의 다음 몇 가지 추가 출력 매개 변수들로 이어질 수 있다. 이것은 주문 순서가 취소될 때 주문 정보를 출력하기 위한 것이다.

        function main() {
            Log("data1", "data2", "data3", "...")
            var data2 = 200
            var id = exchange.Sell(100000, 0.1, "Attached data1", data2, "...")
            exchange.CancelOrder(id, "Attached data1", data2, "...")
            LogProfit(100, "Attached data1", data2, "...")
        }
        
      • 지표 기능 사용 지표 함수에 대해 이야기하기 전에, 먼저 지표가 무엇인지 이해하자. 간단히 말해서, 그것은 이동 평균, MACD 및 ATR과 같은 선입니다. 질문: 이 지표들은 어디서 왔나요? A: 물론 계산됩니다. 질문: 계산의 근거는 무엇일까요? A: K선 데이터에 기초한 계산. Q: 예를 들어보죠? A: 가장 간단한 지표인 이동평균 지표를 예로 들자면, 매일 K선 (즉, 양수 또는 음수 선은 하루를 나타냅니다) 데이터를 지표 계산의 데이터 소스로 사용하면 이동평균 지표 매개 변수는 10이고, 계산된 이동평균 지표는 10일 이동평균입니다. Q: K-라인 BAR의 수가 10보다 작으면 이동 평균 지표를 계산할 수 있습니까? A: 이동 평균 지표가 계산 될 수있을뿐만 아니라, 어떤 지표도 K-라인 데이터 BAR의 수가 지표 기간 매개 변수를 충족하지 않을 때 효과적인 지표 값을 계산할 수 없습니다, 계산 배열의 대응하는 위치가 빈 값으로 채워질 것입니다, 예를 들어,JavaScript언어 전략이 표시됩니다null계산된 지표 데이터를 인쇄할 때

        전략 사각형에 있는 튜토리얼 예가 있습니다.https://www.fmz.com/strategy/125770벡트테스트는 튜토리얼 예제 전략입니다. 벡트테스팅 시스템과 10개 기간 이동 평균에서 생성된 차트를 볼 수 있습니다.

        img

        전략 맞춤 도영, K-라인 그리고 이동 평균 차트.

        img

        Q: 만약 10시간 이동평균을 원한다면요? A: 시간 단위로 K-선 데이터를 사용하는 것은 괜찮습니다.

        일반인의 용어로, 우리가 보는 K-라인은 우리가 디지털화 한 후에 배열입니다. (배열의 개념을 이해하지 못한다면 Baidu를 물어볼 수 있습니다.) 그 각 요소는 K-라인 열입니다. 일반적으로 K-라인 데이터의 마지막 바는 현재 기간의 바이며, 실시간으로 변경되며 완료되지 않습니다 (교환 페이지에 로그인하여 변경 사항을 관찰하여 K-라인을 관찰 할 수 있습니다). 계산된 지표는 또한 K-라인 바와 대응합니다. 위의 예제에서는 지표 값이 K-라인 바에 대응한다는 것을 볼 수 있습니다. 마지막 K-라인 바가 실시간으로 변경되며 계산된 지표도 K-라인 바의 변화와 함께 변경 될 것이라는 점에 유의하십시오.

        FMZ 퀀트 트레이딩 플랫폼에서 TA 라이브러리 (FMZ 플랫폼에 의해 구현된 라이브러리, 도커에 통합되어 다양한 언어를 직접 사용할 수 있습니다) 또는 talib 라이브러리 (옛 talib 지표 라이브러리, JS, C ++ 통합, 파이썬은 직접 설치해야합니다) 를 사용할 수 있습니다. 예를 들어, 위의 예제에서 움직이는 평균을 계산하려면: TA 라이브러리를 사용하세요:

        function main() {
            var records = exchange.GetRecords()
            var ma = TA.MA(records, 10)
            Log(ma)       // print moving average
        }
        

        탈리브 라이브러리를 사용하세요.

        function main() {
            var records = exchange.GetRecords()
            var ma = talib.MA(records, 10)
            Log(ma)       // print moving average
        }      
        

        계산된 지표 데이터 ma는 배열이고 각 요소는 K-라인 배열 (기록) 1 대 1에 해당합니다.ma[ma.length -1]해당됩니다records[records.length - 1], 등등.

        다른 복잡한 지표에도 마찬가지입니다. MACD와 같은 지표에도 주의를 기울여야 합니다.

        var macd = TA.MACD(records)   // In this way, only the K-line data is passed in, not the indicator parameters. The indicator parameters use the default values, and the same goes for other indicator functions.
        

        현재 변수 macd는 2차원 배열입니다. 2차원 배열은 단순히 배열이고, 그 각 요소는 또한 배열입니다. Q: MACD 지표 데이터가 왜 2차원 배열이 되는 걸까요? A: MACD 지표는 두 개의 선 (dif line, dea line) 과 부피 바 (Macd volume bar, 사실 이 부피 바 데이터도 선으로 간주될 수 있습니다) 의 집합으로 구성되어 있기 때문입니다. 따라서 MACD 변수는 다음과 같이 나눌 수 있습니다.

        var dif = macd[0]
        var dea = macd[1]
        var macdColumn = macd[2]
        

        여기에 또한 준비 된 튜토리얼 예제, 관심이 있다면, 당신은 공부 할 수 있습니다:https://www.fmz.com/strategy/151972

        img


관련

더 많은