Ngân sách linh hoạt – Một tài khoản

Biểu tượng công cụ

Google Ads cho phép bạn đặt số tiền ngân sách hằng ngày cho mỗi chiến dịch. Tuy nhiên, một số sáng kiến tiếp thị sẽ có chi phí cố định; ví dụ: "Tôi muốn chi 5.000 USD cho chương trình giảm giá mùa thu". Chiến lược đặt giá thầu giúp bạn có một số quyền kiểm soát đối với cách chi tiêu ngân sách hàng ngày, nhưng không có quyền kiểm soát cách ngân sách được dùng trong suốt chiến dịch.

Ví dụ: nếu chúng tôi chỉ muốn chi 5000 đô la để quảng cáo cho chương trình giảm giá mùa thu và muốn quảng cáo trong 10 ngày, chúng tôi có thể đặt ngân sách hàng ngày là 500 đô la để sử dụng hết toàn bộ ngân sách. Tuy nhiên, giá trị này sẽ giả định rằng chúng tôi sẽ chi tiêu toàn bộ số tiền mỗi ngày VÀ chúng tôi muốn chi tiêu đồng đều. Google Ads không thể cho Google Ads biết rằng bạn muốn chi tiêu phần lớn ngân sách của mình trong vài ngày qua.

Tập lệnh này sẽ tự động điều chỉnh ngân sách chiến dịch của bạn hằng ngày bằng một kế hoạch phân bổ ngân sách.

Cách hoạt động

Thử nghiệm chiến lược ngân sách

Tập lệnh bao gồm một số mã kiểm thử để mô phỏng tác động của việc chạy nhiều ngày. Thao tác này giúp bạn hiểu rõ hơn về điều gì có thể xảy ra khi tập lệnh được lập lịch để chạy hằng ngày trong một khoảng thời gian.

Theo mặc định, tập lệnh này mô phỏng phân phối ngân sách đồng đều 500 đô la đã chi tiêu hơn 10 ngày.

function main() {
  testBudgetStrategy(calculateBudgetEvenly, 10, 500);
  // setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}

Lệnh gọi hàm setNewBudget sẽ có nhận xét, cho biết rằng lệnh gọi hàm này sẽ chỉ chạy mã kiểm thử. Sau đây là kết quả từ ví dụ:

Day 1.0 of 10.0, new budget 50.0, cost so far 0.0
Day 2.0 of 10.0, new budget 50.0, cost so far 50.0
Day 3.0 of 10.0, new budget 50.0, cost so far 100.0
Day 4.0 of 10.0, new budget 50.0, cost so far 150.0
Day 5.0 of 10.0, new budget 50.0, cost so far 200.0
Day 6.0 of 10.0, new budget 50.0, cost so far 250.0
Day 7.0 of 10.0, new budget 50.0, cost so far 300.0
Day 8.0 of 10.0, new budget 50.0, cost so far 350.0
Day 9.0 of 10.0, new budget 50.0, cost so far 400.0
Day 10.0 of 10.0, new budget 50.0, cost so far 450.0
Day 11.0 of 10.0, new budget 0.0, cost so far 500.0

Mỗi ngày tập lệnh sẽ tính toán ngân sách mới để đảm bảo mức chi tiêu ngân sách được phân bổ đồng đều. Khi đạt đến giới hạn ngân sách được phân bổ, ngân sách sẽ được đặt về 0, khiến chi tiêu bị tạm dừng.

Bạn có thể thay đổi chiến lược ngân sách được sử dụng bằng cách thay đổi chức năng được sử dụng, hoặc sửa đổi chính hàm đó. Tập lệnh đi kèm với hai chiến lược dựng sẵn: calculateBudgetEvenlycalculateBudgetWeighted. Cách đặt kiểm thử có trọng số chiến lược ngân sách, hãy thay đổi testBudgetStrategy như sau:

testBudgetStrategy(calculateBudgetWeighted, 10, 500);

Nhấp vào Xem trước rồi kiểm tra kết quả của trình ghi nhật ký. Xin lưu ý rằng chiến lược ngân sách này phân bổ ít ngân sách hơn sớm trong giai đoạn và nhiều hơn trong vài ngày qua.

Bạn có thể sử dụng phương pháp thử nghiệm này để mô phỏng các thay đổi đối với cách tính ngân sách và thử phương pháp phân bổ ngân sách của riêng bạn.

Phân bổ ngân sách

Chiến lược ngân sách calculateBudgetWeighted được triển khai thông qua những cách sau hàm:

function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar, totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / (2 * daysRemaining - 1) ;
  }
}

Hàm này nhận các đối số sau:

costSoFar
Chi phí tích lũy của chiến dịch từ START_DATE đến hôm nay.
totalBudget
Mức chi tiêu được phân bổ từ START_DATE đến END_DATE.
daysSoFar
Số ngày đã trôi qua từ START_DATE đến hôm nay.
totalDays
Tổng số ngày từ START_DATE đến END_DATE.

Bạn có thể viết hàm của riêng mình miễn là hàm đó có các đối số này. Sử dụng các giá trị này, bạn có thể so sánh số tiền bạn đã chi tiêu cho đến thời điểm hiện tại so với cần chi tiêu tổng thể nhiều hơn cũng như xác định vị trí hiện tại của bạn trong tiến trình cho toàn bộ ngân sách.

Cụ thể, chiến lược ngân sách này sẽ xác định phần ngân sách còn lại (totalBudget - costSoFar) rồi chia cho hai lần số ngày còn lại. Chỉ số này được tính toán phân bổ ngân sách vào cuối chiến dịch. Khi sử dụng chi phí kể từ START_DATE, công cụ này cũng tính đến yếu tố "chậm ngày" trong đó ngân sách đã đặt không được chi tiêu hết.

Lập ngân sách thực tế

Khi đã hài lòng với chiến lược ngân sách, bạn cần thực hiện một số thay đổi trước khi lên lịch để tập lệnh này chạy hằng ngày.

Trước tiên, hãy cập nhật các hằng số ở đầu tệp:

  • START_DATE: Đặt giá trị này thành điểm bắt đầu của chiến lược ngân sách. Thông tin này phải là ngày hiện tại hoặc một ngày trong quá khứ.
  • END_DATE: Đặt ngày này thành ngày cuối cùng bạn muốn quảng cáo bằng ngân sách này.
  • TOTAL_BUDGET: Tổng số tiền bạn đang muốn chi tiêu. Giá trị này nằm trong đơn vị tiền tệ của tài khoản và có thể vượt quá tuỳ thuộc vào thời điểm tập lệnh được được lập lịch để chạy.
  • CAMPAIGN_NAME: Tên của chiến dịch để áp dụng chiến lược ngân sách.

Tiếp theo, hãy tắt thử nghiệm và cho phép logic thực sự thay đổi ngân sách:

function main() {
  // testBudgetStrategy(calculateBudgetEvenly, 10, 500);
  setNewBudget(calculateBudgetWeighted, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}

Lập lịch

Lập lịch để tập lệnh này chạy hàng ngày, vào lúc hoặc ngay sau nửa đêm trong đơn vị quảng cáo để phân bổ nhiều nhất có thể ngân sách của ngày tiếp theo. Xin lưu ý rằng tuy nhiên, dữ liệu báo cáo được truy xuất, chẳng hạn như chi phí có thể bị trễ khoảng 3 giờ, vì vậy tham số costSoFar có thể đang tham chiếu tổng số của ngày hôm qua cho một được lập lịch để chạy sau nửa đêm.

Thiết lập

  • Nhấp vào nút bên dưới để tạo tập lệnh trong tài khoản Google Ads của bạn.

    Cài đặt mẫu tập lệnh

  • Lưu tập lệnh rồi nhấp vào nút Preview (Xem trước). Tập lệnh này (của mặc định) mô phỏng chiến lược ngân sách với 500 đô la trong 10 ngày. Kết quả của trình ghi nhật ký phản ánh ngày được mô phỏng, ngân sách được phân bổ cho ngày đó, và tổng số tiền đã chi tiêu cho đến nay.

Mã nguồn

// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @name Flexible Budgets
 *
 * @overview The Flexible budgets script dynamically adjusts campaign budget for
 *     an advertiser account with a custom budget distribution scheme on a daily
 *     basis. See
 *     https://developers.google.com/google-ads/scripts/docs/solutions/flexible-budgets
 *     for more details.
 *
 * @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 2.1
 *
 * @changelog
 * - version 2.1
 *   - Split into info, config, and code.
 * - version 2.0
 *   - Updated to use new Google Ads scripts features.
 * - version 1.0.3
 *   - Add support for video and shopping campaigns.
 * - version 1.0.2
 *   - Use setAmount on the budget instead of campaign.setBudget.
 * - version 1.0.1
 *   - Improvements to time zone handling.
 * - version 1.0
 *   - Released initial version.
 */

/**
 * Configuration to be used for the Flexible Budgets script.
 */

CONFIG = {
  'total_budget': 500,
  'campaign_name': 'Special Promotion',
  'start_date': 'November 1, 2021 0:00:00 -0500',
  'end_date': 'December 1, 2021 0:00:00 -0500'
};

const TOTAL_BUDGET = CONFIG.total_budget;
const CAMPAIGN_NAME = CONFIG.campaign_name;
const START_DATE = new Date(CONFIG.start_date);
const END_DATE = new Date(CONFIG.end_date);

function main() {
  testBudgetStrategy(calculateBudgetEvenly, 10, 500);
//  setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET,
//      START_DATE, END_DATE);
}

function setNewBudget(budgetFunction, campaignName, totalBudget, start, end) {
  const today = new Date();
  if (today < start) {
    console.log('Not ready to set budget yet');
    return;
  }
  const campaign = getCampaign(campaignName);
  const costSoFar = campaign.getStatsFor(
        getDateStringInTimeZone('yyyyMMdd', start),
        getDateStringInTimeZone('yyyyMMdd', end)).getCost();
  const daysSoFar = datediff(start, today);
  const totalDays = datediff(start, end);
  const newBudget = budgetFunction(costSoFar, totalBudget, daysSoFar,
                                   totalDays);
  campaign.getBudget().setAmount(newBudget);
}

function calculateBudgetEvenly(costSoFar, totalBudget, daysSoFar, totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / daysRemaining;
  }
}

function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar,
    totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / (2 * daysRemaining - 1);
  }
}

function testBudgetStrategy(budgetFunc, totalDays, totalBudget) {
  let daysSoFar = 0;
  let costSoFar = 0;
  while (daysSoFar <= totalDays + 2) {
    const newBudget = budgetFunc(costSoFar, totalBudget, daysSoFar, totalDays);
    console.log(`Day ${daysSoFar + 1} of ${totalDays}, new budget ` +
                `${newBudget}, cost so far ${costSoFar}`);
    costSoFar += newBudget;
    daysSoFar += 1;
  }
}

/**
 * Returns number of days between two dates, rounded up to nearest whole day.
 */
function datediff(from, to) {
  const millisPerDay = 1000 * 60 * 60 * 24;
  return Math.ceil((to - from) / millisPerDay);
}

function getDateStringInTimeZone(format, date, timeZone) {
  date = date || new Date();
  timeZone = timeZone || AdsApp.currentAccount().getTimeZone();
  return Utilities.formatDate(date, timeZone, format);
}

/**
 * Finds a campaign by name, whether it is a regular, video, or shopping
 * campaign, by trying all in sequence until it finds one.
 *
 * @param {string} campaignName The campaign name to find.
 * @return {Object} The campaign found, or null if none was found.
 */
function getCampaign(campaignName) {
  const selectors = [AdsApp.campaigns(), AdsApp.videoCampaigns(),
      AdsApp.shoppingCampaigns()];
  for (const selector of selectors) {
    const campaignIter = selector
        .withCondition(`CampaignName = "${campaignName}"`)
        .get();
    if (campaignIter.hasNext()) {
      return campaignIter.next();
    }
  }
  throw new Error(`Could not find specified campaign: ${campaignName}`);
}