초보자, 확인해 보세요 암호화폐 양적 거래로 안내합니다 (2)

저자:니나바다스, 창작: 2022-04-19 16:46:53, 업데이트: 2022-04-20 16:56:43

초보자, 확인해 보세요 암호화폐 양적 거래로 안내합니다 (2)

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

프로그래밍 거래 스크립트

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

    • 중재 전략 간단히 말해서, 짧은 포지션을 보유하면서 기본적으로 긴 포지션을 보유하는 전략은 중재 전략으로 분류 될 수 있습니다. 스팟 크로스 마켓, 선물 크로스 기간, 선물 및 스팟 중재 및 크로스 심볼 중재 등과 같은 많은 특정 유형이 있습니다.

    • 트렌드 전략 간단히 말해서, 트렌드를 추적하고 단일 포지션을 배치하는 전략입니다. 이중 이동 평균, MACD 및 기타 전략과 같이.

    • 반환 전략 예를 들어, 전력망 전략, 변동적인 시장에서 가격 변동으로부터 수익을 얻는 것.

    • 고주파 전략 간단히 말해서, 그것은 시장 미세 구조, 규칙, 기회 등을 발견하기 위해 일부 알고리즘을 통해 고 주파수 거래를 수행하는 전략입니다.

    위의 유형은 거래 전략의 관점에서 분류됩니다. FMZ Quant에서 전략 설계의 관점에서 전략은 다음과 같이 나눌 수 있습니다.

    • 단일 기호 전략 즉, 전략은 BTC 거래 또는 ETH 거래를 하는 것과 같은 하나의 기호만을 작동시킬 수 있습니다.

    • 다중 기호 전략 간단히 말해서, 하나의 전략 논리로 여러 기호를 조작하는 것입니다.

    • 다중 계정 전략 간단히 말해서, 그것은 봇에 여러 교환 객체를 구성하는 것입니다 (플랫폼의 개념은 이전 기사에서 소개되었으며 API KEY로 구성된 교환 객체는 플랫폼 계정을 나타냅니다). 예를 들어, 일부 주문 감독 전략에서는 여러 계정이 함께 작업을 수행합니다. 간단히 말해서, 여러 교환 객체 (회계) 는 하나의 봇에서 관리됩니다.

    • 멀티 로직 전략 예를 들어, MACD 전략, 이동 평균 전략, 그리드 전략 등은 동시에 봇에서 설계됩니다. (물론, 다른 교환 객체를 작동하는 것입니다. 같은 작업을 가진 교환 객체는 특정 전략이 논리적으로 충돌하는지 여부에 달려 있습니다.)

  • 플랫폼 API 인터페이스 프로그래밍 된 거래 스크립트는 플랫폼 계정을 어떻게 작동합니까? 대답은 플랫폼이 열었던 API 인터페이스를 통해 발생합니다. 그렇다면 플랫폼에 개방되는 인터페이스의 종류는 무엇입니까? 지난 기사에서 우리는 플랫폼이 일반적으로 REST 및 Websocket 인터페이스를 가지고 있다고 이야기했습니다. 여기에는 전략 절차 측면의 몇 가지 개념을 추가합니다. 플랫폼 인터페이스는 검증되었는지 (REST 및 Websocket 모두) 확인되었는지 아닌지에 따라 구분됩니다.

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

    • 확인을 필요로 하는 인터페이스 간단히 말해서, 그들은 검증되어야 하는 인터페이스입니다 (API KEY). 이러한 유형의 인터페이스는 개인 인터페이스라고 불립니다. 이러한 유형의 인터페이스는 일반적으로 계좌 자산, 계좌 위치, 미결 주문, 송금, 통화 변환, 레버리지 조정 및 위치 모드 설정 등과 같은 귀하의 계정의 일부 작업 또는 정보와 관련이 있습니다. 이 작업은 검증되어야 합니다.

      FMZ Quant에서 확인이 필요한 API 함수를 호출할 때 (집약되어 플랫폼 검증이 필요한 개인 인터페이스). API KEY의 구성이 잘못되면 이러한 유형의 함수를 호출하면 오류가 보고되고 null을 반환합니다.

    그럼 FMZ 양자 거래 플랫폼에서 이 인터페이스를 어떻게 사용할까요?

    FMZ 퀀트 트레이딩 플랫폼은 통일된 동작과 정의 (K-라인 인터페이스, 깊이 시장 인터페이스, 현재 자산 질의 인터페이스, 주문 인터페이스, 주문 취소 인터페이스 등) 로 플랫폼 인터페이스를 포괄합니다. 이러한 인터페이스는 FMZ 퀀트 트레이딩 플랫폼에서 호출됩니다. FMZ API 기능은 API 문서를 질의하여 볼 수 있습니다: (https://www.fmz.com/api).

    그럼 FMZ Quant에서 통일된 동작과 정의 없이 어떤 플랫폼 인터페이스를 어떻게 사용할 수 있을까요?

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

FMZ API 문서에 있는 모든 API 함수들이 네트워크 요청을 할 수 있나요?

우리는 플랫폼 API가 액세스 주파수의 한계를 가지고 있다고 말할 필요가 있습니다. (예를 들어, 1 초에 5 번). 접근이 너무 자주 될 수 없거나 http 429의 오류가보고되고 액세스가 거부 될 것입니다. 따라서 FMZ Quant에 캡슐화된 플랫폼 인터페이스를 호출하는 것도 한계가 있지만 네트워크 요청을하지 않는 API 기능을 호출하는 것은 그러한 한계가 없습니다.
FMZ Quant의 모든 API 기능은 네트워크 요청을 할 수 없습니다. FMZ의 일부 API 기능은 현재 거래 쌍, 계약 코드 및 지표 계산 기능 설정, 교환 객체 이름을 획득하는 등 일부 로컬 설정을 수정합니다. 기본적으로, a 함수의 사용에서 네트워크 요청이 이루어질지 결정할 수 있습니다. 플랫폼 데이터를 획득하거나 플랫폼 계정을 운영하는 한 네트워크 요청이 이루어집니다. 이 인터페이스들은 모두 호출 주파수에 주의를 기울여야합니다.

  • FMZ Quant에서 API 함수를 사용하는 몇 가지 일반적인 문제와 경험에 대해 이야기 해 봅시다.

    • 결함 허용 이것은 가장 일반적인 오류이며, 수많은 초보자를 괴롭히고 있습니다. 종종 전략 백테스트가 좋고 모든 것이 정상입니다. 왜 봇이 잠시 동안 실행된 후 비정상적으로 작동합니까?

      img

      전략을 작성할 때, 인터페이스에 의해 반환 된 데이터를 확인해야합니다. 예를 들어, FMZ Quant에 티커를 얻는 코드 (플랫폼 인터페이스에 직접 액세스하기 위해 자신의 프로그램을 작성하는 것과 동일합니다):var ticker = exchange.GetTicker()만약 우리가 데이터를 사용할 필요가 있다면Last(최근 가격) 변수ticker(당신은 함수 GetTicker의 반환 구조를 참조할 수 있습니다), 우리는 데이터를 얻을 필요가 있습니다 (newPrice는 무엇입니까? new: 최신; 가격: 가격; thats 맞습니다, 그들을 결합!)

      이제, 기능이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 {
          // data is null, so no operation will make no problem 
      }
      

      뿐만 아니라GetTicker인터페이스는 오류 용인 처리해야 하지만 네트워크 요청과의 인터페이스는 반환 값에 대한 오류 용인 처리 (함수의 반환 값을 사용하는 경우) 를 해야 합니다 많은 오류 용인 방법이 있습니다._C()함수 (FMZ API 문서를 참조하십시오) 를 작성하고 자신의 오류 용인 메커니즘과 논리를 설계합니다.

      사용에 관하여_C()많은 새로운 학생들이 또한 잘못 사용할 가능성이 높습니다._C()함수는 함수 참조가 아니라 함수 호출입니다. 간단하게 말하자면:_C(funcName, param1, param2); 호출은 정확합니다; funcName는 괄호가 없으며, param1과 param2는 funcName 함수로 가져오기 위한 매개 변수입니다._C(funcName(param1, param2)); 호출이 잘못되었습니다; 일반적으로 초보자 FMZ API 문서를 신중하게 읽지 않으면 다음과 같이 작성됩니다.

    • 스팟 시장 구매 주문 금액

      초보자 또한 쉽게 사물 시장 구매 주문의 주문 금액에서 실수를 할 수 있습니다. 이전 기사에서 언급했듯이, 사물 시장 구매 주문의 주문 금액은 일반적으로 돈 금액입니다 (단순히 몇 가지 플랫폼이 다른 설정을 가질 수 있으며 일반적으로 이러한 특별한 플랫폼 설정을 FMZ API 문서에서 설명 할 것입니다). 예를 들어, 나는 테스트를 위해 OKEX V5 시뮬레이션 봇을 사용했습니다:

      거래 쌍을 이렇게 설정하세요:LTC_USDT

      function main() {
          exchange.IO("simulate", true)   // switch to OKEX simulated bot 
          exchange.Buy(-1, 1)             // the price is -1, representing the placed order is market order; the amount of 1 means the order amount of 1 USDT
      }
      

      플랫폼은 일반적으로 주문 금액에 제한을 가지고 있기 때문에 제한보다 작은 금액의 주문은 배치되지 않습니다 (예를 들어, 바이낸스 스팟은 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 Quant에 전략을 작성하는 예를 들어, 먼저 API 문서에 대한 설명을 살펴 보겠습니다:https://www.fmz.com/api#exchange.setdirection...

      img

      왜냐하면 순서 배치 함수는Buy그리고Sell그러나, 선물 (물론, 스팟에 대한 문제가 없습니다, 스팟은 단지 구매 및 판매를 가지고 있습니다) 는 긴 오픈, 긴 닫는, 짧은 오픈, 짧은 닫는 방향이 있습니다, 그래서 분명히 BuySell는 많은 방향으로 작업을 표현할 수 없습니다, 그 다음 함수를 도입하는 것이 필요합니다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 to a quarterly contract 
          exchange.SetDirection("sell")
          var id = exchange.Sell(-1, 1)    
          Log("placed market order, executed, get positions", exchange.GetPosition())    
          exchange.SetDirection("closebuy")   // use closebuy and Sell together, yes, no problem 
          exchange.Sell(-1, 1)
      }
      

      img
      여기까지 와서는, 당신은 물어볼 수 있습니다:" 나는 포지션을 가지고, 그리고 함께 클로즈 바이와 판매를 사용, 그래서 왜 오류가 보고되고 나는 포지션을 닫을 수 없습니다?"나는 말할 것입니다:오른 방향으로 포지션을 닫습니다! 당신은 긴 포지션을 닫았습니다. 또한, 오류는 다른 상황에서도 발생할 수 있습니다: 가까운 위치 방향 설정이 정확하고, 주문 배치 기능의 사용도 정확하며, 또한 방향에서 위치를 유지하지만 오류는 여전히보고됩니다. 그 이유 는: 프로그램 이 많은 오더 를 배치 했기 때문 이고, 처음에는 오더 가 실행 되지 않았으며, 클로즈 포지션 의 오더 는 현재 시장 에 있으며 실행 을 기다리고 있다. 그 때, 프로그램 은 계속 포지션을 닫아, 클로즈 포지션 과잉 에러 를 불러일으킬 것이다.

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

      FMZ의 정보 디스플레이에 대해 이야기 해 봅시다. FMZ Quant에서 정보를 표시하는 데 주로 두 개의 장소가 있습니다.

      • 상태 표시줄 봇이 시작되면 bot 페이지가 다음과 같이 표시됩니다.

        img

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

      • 로그 바 또한 bot 페이지에도 있습니다. 아래 그림에서 보시는 것처럼요.

        img

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

        1. 일반적인 로그; FMZ 전략은 로그 함수를 사용하여 전략 로그에 출력하고 인쇄합니다.

        img

        1. 주문 로그exchange.Sell/exchange.BuyFMZ 전략에서 로그에 있는 기록을 자동으로 출력합니다.

        img

        1. 취소 로그exchange.CancelOrderFMZ 전략에서 사용되고 취소 로그는 로그에 자동으로 출력됩니다.

        img

        1. 오류 로그: FMZ 전략이 실행되고 네트워크 요청 인터페이스가 호출 오류가 발생하고 예외가 던지면 (throw 명령어와 같이) 오류 로그는 로그에서 자동으로 출력됩니다.

        img

      FMZ API 함수 중 로그 출력을 생성 할 수있는 함수, 예를 들어 Log ((...), exchange.Buy ((Price, Amount), exchange.CancelOrder ((Id) 등은 필요한 매개 변수 다음 몇 가지 추가 출력 매개 변수로 이어질 수 있습니다. Exchange. CancelOrder ((order[j].Id, orders[j]); 주문 순서가 취소 될 때 추가로 주문 정보를 출력해야합니다.

      function main() {
          Log("data1", "data2", "data3", "...")
          var data2 = 200
          var id = exchange.Sell(100000, 0.1, "additional data1", data2, "...")
          exchange.CancelOrder(id, "additional data1", data2, "...")
          LogProfit(100, "additional data1", data2, "...")
      }
      
    • 지표 기능 사용 지표 함수에 대해 이야기하기 전에, 먼저 지표가 무엇인지 이해하자. 간단히 말해서, 그것은 이동 평균, MACD 또는 ATR과 같은 선입니다.

      Q:그 지표들은 어떻게 생성되는가? A: 계산에 의해 생성된 것입니다.

      질문: 어떤 기준으로 계산되나요? A: K선 데이터

      Q: 예를 들어 주시겠습니까? A: 가장 간단한 이동 평균 지표를 예로 들겠습니다. 우리가 매일 K-선 (즉, 양선 또는 인 선은 하루를 나타냅니다) 데이터를 지표 계산의 데이터 소스로 사용하면 이동 평균 지표 매개 변수는 10 이므로 계산된 이동 평균 지표는 10 일 이동 평균입니다.

      Q: K-라인 BAR의 수가 10보다 작으면 이동 평균 지표를 계산할 수 있습니까? A: 이동 평균 지표가 계산될 수 있을 뿐만 아니라 어떤 지표도 K-라인 데이터 BAR의 수가 지표 기간 매개 변수를 충족하지 않을 때 효과적인 지표 값을 계산할 수 없으며 계산된 배열의 대응하는 위치가 빈 값으로 채워질 것입니다.null표시될 때JavaScript전략은 계산된 지표 데이터를 인쇄합니다.

      광장에서 가르치는 예가 있습니다.https://www.fmz.com/strategy/125770이 교육 예제 전략을 다시 테스트해보세요. 그리고 여러분은 백테스트 시스템과 10기 이동평균으로 생성된 차트를 볼 수 있습니다.

      img

      전략 맞춤 도영, K-선 도영 및 이동 평균 차트:

      img

      Q: 만약 10시간 이동평균을 사용한다면 어떨까요? A: 시간 단위의 K-라인 데이터를 사용하세요.

      간단히 말해서, 우리가 보는 K-라인은 우리가 디지털화 한 후에 배열입니다. 배열의 개념이 이해되지 않으면 Baidu에서 검색 할 수 있습니다. 배열의 각 요소는 순서대로 배열된 K-라인 바입니다. 배열의 첫 번째 요소는 현재 시간에서 가장 멀리 있으며, 배열의 마지막 요소는 현재 시간에 가장 가깝습니다. 일반적으로 K-라인 데이터의 마지막 바는 현재 기간의 바이며, 이는 실시간으로 변경되며 완료되지 않습니다. 계산된 지표는 또한 K-라인 바와 1:1 대응합니다. 위의 예제에서는 지표 값이 K-라인 바와 일치하는 것을 볼 수 있습니다. 마지막 K-라인 바가 실시간으로 변경되며 계산된 지표도 K-라인 바의 변화와 함께 변경 될 것임을 유의하십시오.

      FMZ 양자 거래 플랫폼에서 TA 라이브러리 (FMZ가 구현한 라이브러리, 도커에 통합되어 다양한 언어로 직접 사용할 수 있습니다) 또는 talib (옛 유명한 지표 라이브러리 talib, JS, C ++에 통합; 파이썬이 추가로 설치되어야합니다.) 를 사용할 수 있습니다. 예를 들어, 위의 예제에서 평균을 계산하면: FMZ TA 라이브러리를 사용하세요:

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

      탈리브를 사용하세요.

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

      계산된 인덱스 데이터 ma는 배열이고 각 요소는 K-라인 배열 (기록) 에 하나씩 대응합니다.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, and no indicator parameters are passed in. The indicator parameters use the default values, and that is the same for other indicator functions
      

      이 때, 변수 macd는 2차원 배열입니다. 2차원 배열은 단순히 배열이고, 그 각 요소는 또한 배열입니다.

      Q: MACD 지표 데이터가 왜 2차원 배열일까요? A: MACD 지표는 두 선 (dif line와 dea line) 과 부피 바의 집합으로 구성되어 있기 때문에 (MacD 부피 바 데이터는 실제로 선으로 간주 될 수 있습니다.) 따라서 MACD 변수는 다음과 같이 나눌 수 있습니다.

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

      여기에 또한 준비 된 교육 예제; 당신이 관심이 있다면, 당신은 그것을 연구 할 수 있습니다:https://www.fmz.com/strategy/151972

      img


더 많은